[rspec-users] Controller spec: testing that scope is set

David Chelimsky dchelimsky at gmail.com
Sun Apr 19 21:00:16 EDT 2009


On Sun, Apr 19, 2009 at 7:19 PM, Michael Schuerig <michael at schuerig.de> wrote:
> On Monday 20 April 2009, David Chelimsky wrote:
>> On Sun, Apr 19, 2009 at 5:41 PM, Michael Schuerig
> <michael at schuerig.de> wrote:
>> > On Sunday 19 April 2009, Zach Dennis wrote:
>> >> On Sun, Apr 19, 2009 at 2:09 PM, Michael Schuerig
>> >
>> > <michael at schuerig.de> wrote:
>> >> > On Sunday 19 April 2009, Zach Dennis wrote:
>> >> >> On Sun, Apr 19, 2009 at 12:27 PM, Michael Schuerig
>> >> >
>> >> > <michael at schuerig.de> wrote:
>> >> >> > In a Rails controller I set the scope on a model class in an
>> >> >> > around filter. I have defined expectations on the model
>> >> >> > classes, and ideally, I would add a further expectation for
>> >> >> > the scope. Is this already possible in some way? How would I
>> >> >> > go about adding support a scope expectation?
>> >> >>
>> >> >> How are you setting the said scope?
>> >> >
>> >> > In an around filter. However, I don't want to test the around
>> >> > filter mechanism, it might as well be rack middleware instead.
>> >>
>> >> Sorry, I don't know what scope means to you in your app. Can you
>> >> share your around_filter?
>> >
>> > Oops, sorry, I assumed the concept from ActiveRecord would be
>> > familiar.
>>
>> It *is* familiar, but setting a model scope from the controller
>> violates the widely-accepted guideline of skinny controllers and fat
>> models. I'm guessing that's why Zach wasn't sure what you were
>> talking about.
>
> My controllers are anorexic. The functionality I'm trying to spec is
> completely generic, I just mix it into the controller.
>
> [snip]
>> > Somewhere in QueryScope
>> >
>> > def query_scope(options = {}, &config_block)
>> >  model_class = extract_resource!(options)
>> >  builder = QueryScopeBuilder.new(config_block)
>> >  around_filter(options) do |controller, action|
>> >    req = builder.build_request_conditioner(controller.request)
>> >    controller.instance_variable_set(:@offset_limit,
>> > req.offset_limit) model_class.send(:with_scope, :find =>
>> > req.find_options, &action) end
>> > end
>>
>> Unless I'm mistaken, it is code like this outside models that was the
>> underlying motivation for adding named scopes to active record. The
>> reason it is problematic is that it tends to result in a lot of
>> duplication outside the models, and makes the controllers really hard
>> to understand.
>
> You are mistaken as there is no duplication at all. Among other things,
> I have Rack middleware that maps request like (appropriately escaped)
>
>  /resource/?[?name='Dav*'][/name]
>
> to a params hash like
>
>  { :query => [{:attribute => 'name', :op => '=', :target => 'Dav*'}],
>    :order => [{:attribute => 'name'}] }
>
> This, in turn, is interpreted by a RequestConditioner (bad name) which
> in this case would, with the help of some mappings passed to it, return
>
>  rc.conditions == ["(firstname || ' ' || lastname) LIKE ?", 'Dav%']
>  rc.order      == 'lastname, firstname'
>
> As the last step, these pieces are used to define a scope around certain
> controller actions. I could pass them explicitly to, say, #find, but
> then I'd have to manually merge them with other conditions.
>
> As to whether this functionality belongs in the model -- I am against
> it. What I've described is an adapter layer that translates from one
> representation of a query to another. It is not at all related to the
> core logic enclosed in the models.
>
>
>> Consider this alternative:
>>
>> describe PeopleController do
>>   describe "GET index" do
>>     it "assigns a list of all people filtered by virtual name
>> attributes" do people = [mock_model(Person)]
>>       Person.stub!(:all).and_return(people)
>>       people.should_receive(:with_virtual_names).and_return(people)
>>       get :index
>>     end
>>   end
>> end
>>
>> class PeopleController
>>   def index
>>     @people = PeopleController.all.with_virtual_names
>>   end
>> end
>
> That code is sclerotic. I'm building a RIA-client that only requests
> JSON-formatted data from the server. Say, I add a date of birth column
> to the people grid. Then the most I want to (and have to) do is ensure
> that the requisite attribute is whitelisted for querying and contained
> in the response data. (Yes, I have JSON "views" with accompanying
> specs.)
>
> Taking your non-generic approach, I'd have to repeatedly write and
> explicitly test, very similar code. Consider adding date of birth for
> sorting and filtering to your example. Then consider writing another
> controller that does roughly the same for movies with titles and release
> dates. You'll end up with repetitive code. Of course, you're going to
> factor out the repetition -- and that's where I already am.
>
> So, long story short, I still think I could make good use of a way to
> define an expectation for a specific scope in effect during a #find.
> Apart from my current case, this would make it possible to check on
> dynamic scopes introduced in Rails 2.3.

So what does the controller's index method actually look like?

>
> Michael
>
> --
> Michael Schuerig
> mailto:michael at schuerig.de
> http://www.schuerig.de/michael/
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the rspec-users mailing list