Drawing the line between the model and the Controller
I'm building this restful application using Ro开发者_StackOverflow中文版R, and am finding it a bit difficult to draw a line between things that should go on the model, and things that should go on the controller.
As an example, I have 7 methods on my controller (the ones that make it restful i.e. index(), show(), create(), update()...), and often find that it's necessary to add extra methods, and do so by creating them as members.
What I'd like to accomplish here, is gather experience from you guys on what goes where (i.e. should I stick all the database interactions on the model, and simply call those methods from the controller?)
Also, by adding things that don't involve DB to my controller i.e. I want to make an HTTP call to screen-scrape some data from a website.
HTTP calls can get big and messy. Should all this go to my controller, or should this go an a separate class or module, and only be included to my controller so it can be called?
If so, what would be the best approach to do that?
I'm a bit confused with all this, so it would be great to have somebody's input.
Thanks in advance
It is a part of Domain Driven Design.
The Domain is the sphere of knowledge that defines the area that the application is attempting to work with and solve problems for.
The Model layer is considered the Domain layer. It is here that all the rules that define the Domain or business logic are kept. The model acts as a filter between the real data and the rest of the app in a way that defines the domain.
The implementation details of the Domain (mySQL or MSSql or Webservice or Xml file or external web page or whatever) are hidden by the Model.
The Controller is just the messenger. Its job is to take messages from the user and pass them to the Model. The Model comes up with a reply and the Controller works out the best way to pass this on to the user.
The View is like the make up artist, just making sure that the data looks good and presentable for the user.
The website that you are scraping could be considered to be part of the Domain. This site contains knowledge that defines the world that your app is defining. The screenscraping process is sculpting that knowledge in a way such that it will relate to the rest of the world view that your app is defining. The Controller doesnt care where this knowledge comes from, it will just pass the message on to the View. The View will fuss over the data and make it pretty and send it off to the user, who is completely oblivious to the whole process and just sees a pretty web page!
Generally speaking, a good approach (no religion flame, plz) is to have thin controllers and fat models. In that way you can also easily test "the things" the models are supposed to do...
The scraping stuff should go in a non ActiveRecord model, and the controller should just invoke methods of this model.
There is a nice example of a tableless AR model, and one of a non-AR model on railscasts.
So, your controller would do something like:
def index
@some_things = SomeThing.all
end
def show
@some_thing = SomeThing.find params[......]
end
And your SomeThing
model would implement the needed logic.
I stick to the rules of thin controller and fat models.
Given a restful approach I keep all controllers to this standard and have no further methods in them outside the default. If I require new functionality and note the methods do similar things (or would have a similar naming e.g group_add , group_remove ) I create a new controller and use existing models and create new methods in the model.
This also allows a restful approach to these further actions in a meaningful way and specifically each action has a narrowly defined spec for its operation, it will never do more than one thing. Nothing worse than using an API call that does two things dependent upon how its called.
An approach I use is to handle the request as 'fast' as possible by using as little code as needed and abstracting complex tasks/operations to the model.
When I have used SOAP calls from Rails, which is similar to what you're talking about in a way, I treated those as a source of data, so to my mind they belonged in the model. You might also choose, if the functionality is somewhat generic, to write a plugin to do that job as well, or to find a plugin that does most of what you want already and utilise that.
If in doubt think of your model as the application and your view/controller as the interface. If its not clearly interface it probably belongs in the Model.
This question may help.
I also prefer skinny controllers and fat models... A good tool to help you enforce this rule is the inherited_resources gem by José Valim. I suggest you have a look at it: http://github.com/josevalim/inherited_resources
精彩评论