Pat, Thanks for reply. The one year ago thing was a really bad example. Using your terminilogy it looks like a rule that changes what my app does. But I was talking about a change in what the app is; i.e. a business rule.
I definitely don't want to have business rules in controllers. From my viewpoint in MVC the controller is a conduit that allows the business domain encapsulated by the model to be presented in views and in reverse allows interaction with views to communicate with the model. In Rails though its very easy for the business domain to creep into the controller. I'm beggining to think that Rails got this wrong. Perhaps it should have specified a restrictive api between the model and the controller, I've been thinking of something like get_collection get_object get_new_object By giving completely open access to anything in the model including all classes its real easy for controllers to get real messy. I think the emergence of Presenters as well as skinny controllers is symptomatic of that problem With a resource based approach the controller really should only be requesting resources or more accurately representations of resources. It shouldn't be creating/specifying representations of resources. That is outside the responsibility of a controller. Again using your terminology REST restricts what an application does by using a standard set of verbs to do things. Now in Rails we can pollute this by putting all sorts of stuff in our restful methods, but really we shouldn't. Instead we should use the expressivness of what 'is' to get our functionality. If we do this then our controllers can be ultra skinny and our controller specs should be much less brittle. To change what our app 'does' we then add new routes, controllers and views to show a different representation from our model but still using our standard verbs. If controllers only use the restrictive api I've suggested and we combine this with a 'presenter' layer (when required) on top of our model. then controller specs really can be very straightforward and focus on their key responsibilities which are getting something and controlling i.e. routes. I'll try and give a better example. In my business domain I have products and some of these products have refills which are also products. Generally when I want to look at all products I don't want to see the refills. This is because the refills are bought and specified through their product. So using tags when I want to find 'all' products I'll actually do the following bizzarre thing Product.find_tagged_with('refill', :exclude => 'refill') Now generally in Rails this will be done in my controllers index method, and with rspecs scaffold code we'd mock Product and test that this method was called the correct way. So as my call has changed from Product.find(:all) to this new call I have to change my controller spec. Now changing what all products means has nothing to do with controllers and everything to do with models. What my controller should have done is called Product.get_collection. Then when I change my definition of what get_collection does then yes I have to update my model spec, but that makes sense, and my controller and its specs remain the same. I don't see controller specs as being fixed, but I do think they should only need to change when something a controller is responsible for changes. Generally this is routing - controlling where we go - which is fundamentally how web applications do things. Anyhow hope that makes sense and once again thanks for the input much appreciated Andrew 2008/12/11 Pat Maddox <perg...@gmail.com> > "Mark Wilden" <m...@mwilden.com> writes: > > > On Thu, Dec 11, 2008 at 4:33 AM, Andrew Premdas <aprem...@gmail.com> > wrote: > > > > it "should find all posts" do > > Post.should_receive(:find).with(:all).and_return([...@post]) > > do_get > > end > > > > Now this last spec "should find all posts" is nosy is far as I'm > concerned in that its specifying how the model should get all the > > posts (i.e. white box testing) rather than checking the result > i.e. that its got @post back. So now if I change the model so that > > "all posts" is for example "all posts in last year" because there > is a new business rule that we don't show posts over a year old > > then my controller spec fails. > > > > I think this is probably correct as is. > > > > When specing a controller, it's correct BDD to specify how it interacts > with other objects. If the controller itself wants all posts in the > > last year, it's OK to test that. The fact that only this year's posts are > of interest is a presentation issue - it's not an essential > > characteristic of the data. It's not the model's job to decide that all > clients should get back posts in the last year, and hence that's > > what its find method should return. > > > > All business rules don't reside in the model. As soon as you say "we > don't SHOW posts over a year," you're talking about a presentation > > rule, not a model rule. Controllers mediate between data and screen - > they're responsible for getting the data to be shown. That code should > > exist in the controller and be tested there. > > > > On the other hand, the controller should not necessarily be responsible > for defining what constitutes "all posts in the last year." That > > should very likely be a named scope. > > > > This is all just my humble opinion, of course, and might be utter rubbish > in any particular real world situation. > > > > ///ark > > > > _______________________________________________ > > rspec-users mailing list > > rspec-users@rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > I agree with this. You generally don't want to screw with the meaning > of AR::Base.find. That's really only for situations where you want some > uniform, transparent behavior (acts_as_versioned, acts_as_paranoid, > etc). > > The view shouldn't really care about this stuff either...it should just > take a list of posts and display them. > > It's up to the controller to ask the model for what it wants to push to > the view. So your finder can be something like Post.since(1.year.ago) > or whatever. > > Andrew, I've noticed a theme in your posts that suggests you feel you > needn't ever change controller specs. That's just not true. Models > are a distilled representation of the domain, and controllers give > meaning to it in the context of the application you're working on. > Models are what your app *is* and controllers are what your app *does*. > When you change what your app does, you're going to have to change some > specs and production code along with it. > > Keep in mind that if you went with a state-based test, you would *still* > have to modify the controller spec. It wouldn't be good enough to > expect a post to be displayed. You'd have to create a post with a > created_at of over a year ago, and one within the last year, and expect > that the former is not shown while the latter is. > > Also, I'd like to point out that if you *really* wanted Post.find(:all) > to only return posts in the last year, you wouldn't actually have to > change the controller spec :) You would just have to write a model spec > for that behavior. > > Pat > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
_______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users