This is a complicated question with many possible answers, so I'll break down my situation into simple bullet points to help narrow down the solution:
My Rails App Has the Following 'Objects'
Author
Feed
Update
FeedTypes
The Objects are Related Like So:
Authors can have 1 or more Feeds
Feeds can have one or more Updates
A Feed has one feedType
Example Setup:
Author: Levi Hackwith
Feed: view-source:http://www.twitter.com/statuses/user_timeline/opnsrce.xml
FeedType: Twitter
Update: The tweets inside the Feed
My problem and My Questions:
Problem:
I need to parse the above-mentioned feed and store each tweet in the updates table. To parse the feed, I was thinking of writing a custom Feed class which would get inherited by TwitterFeed, FacebookFeed, TumblrFeed, etc.
However, I'm not sure if this is the 'Best Practice' for solving this kind of problem.
Questions:
When is it appropriate to develop a custom class to perform an action in RoR (as opposed to going through the Model or Controller)?
If this situation does not call for a custom class, which element should I apply the parsing logic to? The model or the controller?
If this is an appropriate situation for a custom class, where in my rails application should I store it (in other words, what's the right 'convention')?
You are probably going to have a background task invoked from time-to-time to check all the feeds, fetch new updates and store those in database. This task is completely separate from controllers and it should be possible to invoke it without any controller logic.
Your abstraction looks fine. You can further have something like XmlFeed < Feed if several feeds share a common XML structure.
1) Controllers should talk to database/models and pass relevant data to the view to render. Everything else should be either in a model, helper or library.
2) Are you asking where the parsing logic belongs to? In MVC, I think this would belong under the Model and/or a helper class, but definitely not the controller.. it's not its responsibility.
3) Classes holding data go into app/models. Classes that have nothing to do with holding data, go into the lib directory.
Don't shy away from using a custom class if it's appropriate. If you need another a class, then add one, the fact you are using rails is not relevant to that decision.
Related
I am currently going through Hartl's Rails Tutorial, and through the first 10 chapters or so have gotten used to the convention of putting most of the actions/methods in the controller. Currently, as the book is going through and defining a feed method for the Microposts, the method is placed with the User.rb model instead. As I am relatively new to the world of rails (and programming in general), I was wondering what the rationale or convention followed for putting this method (copied below) in the Model?
The method placed in the User.rb model:
def feed
# This is preliminary. See "Following users" for the full implementation.
Micropost.where("user_id = ?", id)
end
There is actually quite some contention on what code to put where, but in general, there are some easy guidelines to follow.
Does the method have to know some detail about the underlying data structure? Put it in the model.
An easy way to determine this is when it uses ActiveRecord methods like find, where, or specific columns in the database. By keeping this logic in the model, that means if you need to change the underlying datastore, you only have to change the model.
Does the method have some say in how a page is going to be rendered? Put it in the controller.
Generally, controllers should be pretty thin, pushing data to views and saving form data back to models.
While (if I remember correctly) Hartl does not take about non-rails classes, don't be afraid to put 'business logic' outside of the rails structure. You can create a app/lib or app/services or app/x directory and put plain old ruby objects in there, which can then be called from your controllers and models to handle those things they are good at.
Aim to 'push' things 'up' into the model as much as possible, then they will be repeated less and available to more. Don't just use models for Active Record database tables.
You can often unit test models easier.
Another 'next' place to put stuff that is shared is in /lib
I need some help as I seem not to be able to grasp the concept.
In a framework, namely Yii, we create models that correspond to database tables. We extend them from CActiveRecord.
However, if I want to create a class that will get some data from other models but then will do all the computations based on those results and do something with them... then how do I proceed?
I want to clearly divide the responsibility so I don't want put all the calculations in source db based models. Basically the idea is that it will be taking some stuff from some models and then updating another models with the results of the calculations.
What do I do?
Keep all the calculations in some controller and use required models? (Hesitant about this because there is a rule to keep controller slim)
Create a none db model and then work from there (how?)?
Do something else (what?)?
Thanks for any help!
For you to use the Yii interpretation of Model, you will have to create class, which depends on CModel. It is an abstract class, thus you will be required to implement attributeNames() method.
To use other "Models" with this new structure, you will need to inject them in constructor, or right after your custom model has been created.
In real MVC model is a layer, which mostly contains two sets of classes with specific responsibilities: domain business logic and data access operations. Objects which are responsible for Domain Business Logic have no clue where the information is stored and where it comes from. Or even if there is such a thing as "database".
This video might explain a bit: https://vimeo.com/21173483
For example: Let's say I'm grabbing a list of names and saving it to an NSMutableArray. Do I implement the method of actually calling the server to fetch the data in the controller (UIViewController) or the model(Friends object)?
It's a design decision that depends on what you're trying to accomplish. If your model only makes sense in the context of a single service, or if you want your model to provide access to all the data on the server, then build the connection to the server into your data model. This might make sense if you are, for example, building a client for a service like Twitter or Flickr.
On the other hand, if you're just grabbing a file from a server and that's the end of it, it may make sense to do the communication in the controller. Controllers tend to be less reusable and more customized for the particular behavior of the application. Keeping the specifics about where the data comes from out of the model makes the model more reusable. It also makes it easy to test -- you can write test code that just reads a local file and stores the data in the model.
That's a good question. I think the best way is through a controller because it decouples your model from requiring the other model to be present for it to work properly. Although I don't think you violate "proper mvc" by doing it in the model either.
I think you want to put it in the model. What you'll do is interrogate the model for the data and then the model will handle how to populate itself whether it's from an internal data store or an external one (like a server).
One approach is to use the repository pattern. To do this, you create Repository objects in your Model folder and you place all of you database-related methods in them. Your controllers call the repository classes to get the data. This allows you to separate the real model objects from the database accessing methods.
I use the MVCS pattern (Model-View-Controller-Store), which I discovered in Aaron Hillegass's book "IOS Programming: The Big Nerd Ranch Guide" (http://www.bignerdranch.com/book/ios_programming_the_big_nerd_ranch_guide_rd_edition_)
The store is specifically designed to fetch the data, whether it comes from a server, a local file, a persisted collection, a database, etc.
It allows to build very evolutive applications. For example, you can build your application based on a web service, and the day you want to persist your data, you juste have to modify the store, without having to modify a single line of code in your controller.
It's a lot like the Repository Pattern (http://msdn.microsoft.com/en-us/library/ff649690.aspx) (cf BobTurbo's answer)
I'd personally make a DAO, or data helper class. It's very hard to follow the strict MVC in objective C when things get more complicated. However, putting it in the model or the VC is not wrong as well.
I want to refer to $this->Model-> ... in the controller. But I want to make the functions generic, so how can I use do that dynamically? I tried $this->$modelname but of course that didn't work.
The CRUD functions will be generic to all models and thus all controllers, with overriding in a couple of cases.
EXAMPLE: Two controllers, one for each model -- Letter and Email. There is letter controller and email controller. Each has CRUD functions. The views are essentially identical, except the models track different information for each (e.g., Letter with send_method). The only thing that varies between them is the fields. I have automated that part, but the controllers are essentially the same thing as one another except for a few minor variations. I want to have a parent class and have it use the model name of the particular model, so I don't have to keep making changes to every controller every time I make a change. But in some instances I need to refer to $this->Model-> ... and I don't know how to do that.
Commplete rewrite based on clarification of OP
At the top of letters_controller.php add:
$this->defaultModel = 'Letter';
And in emails_controller.php add:
$this->defaultModel = 'Email';
In either controller, to reference the model, call
$this->{$this->defaultModel}->function();
Sounds like you're trying to re-invent the wheel: have you checked out the CakePHP Scaffolding section?
As my Cocoa skills gradually improve I'm trying not to abuse the MVC as I did early on when I'd find myself backed into a hole built by my previous assumptions. I don't have anyone here to bounce this off of so hoping one of you can help...
I have a custom Model class that has numerous & varied properties (NSString, NSDate, NSNumber, etc.). I have a need to serialize the properties for transmission. Occasionally as this data is being processed for serialization a questions may come up that the user will need to respond to (UIAlertView, etc.)
Without bogging down in too many more specifics where does this code belong?
Part of me says Model because it's about persistence of data - in a way.
Part of me says View because it's another interpretation of the core data (no pun intended) contained within the model. And the user will have to interact with dialogs on occasion as data is processed
Part of me says Controller because it's managing the transformation of data between model & view.
Is it a combination of all three? If so how would communication be handled between classes as the data is being processed? NSNotifications? Direct method calls?
This may be something that you'd want to use the Visitor pattern for -- http://en.wikipedia.org/wiki/Visitor_pattern -- because you might eventually want to use different sorts of serialization for different things and you can have different visitor classes rather than a lot of special cases in the model code.
Here's a discussion of the Visitor pattern in objective-c/cocoa: http://www.cocoadev.com/index.pl?VisitorPattern
Here's an (old!!!) article from Dr. Dobbs about the visitor pattern in objective-c: http://www.drdobbs.com/184410252
The reason that the problem you're working on doesn't fit well into the MVC paradigm is that the serialization that you're doing is like a view on a stream-based rendering surface and it is displayed. Sometimes, this can be done really smoothly in the model but sometimes it's more complex and you need to look at your case to figure out which one it is.
Frequently, the transmission/web service (or whatever) code you're using will have its own handler for this data, for example ObjectiveResource adds a serialization and deserialization handler that works as an extension to NSObject that enables it to do a lot of this stuff transparently, and you might look into that code (particularly the ObjectiveSupport part) if you're trying to do this more generically.
Typically almost all application specific code belongs in the controller. The controller should interact and observe (via notification) the model and update the view as appropriate.
If you are doing model processing such that it is something that might be re-used in another app with the same model, then that processing could be in the model.
Views can be laid out in Interface Builder or created in code and/or be subclassed for custom drawing, but they should not have application logic and would not interact directly with the model.
I would suggest putting the serialising code in the model. If the process fails it can report that to whatever's listening to it (the view / controller) which can then present the UIAlertView, correct the problem and re-submit for another attempt.
I'd say in the model.
The call to serialize the data will be done by the controller. If the data cannot be serialized then the model should return an error which the controller then has to handle.