Note that there are some explanatory texts on larger screens.

plurals
  1. POBest way to test named scopes in Rails4
    primarykey
    data
    text
    <p>As a part of the migration from Rails 3.2 to Rails 4, all named scopes need a proc block. Read more here: <a href="http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#active-record" rel="nofollow">http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#active-record</a></p> <p>I had missed updating a scope in one of my models, which ended up biting me in production after my migration. So I wanted to figure out how to test this issue, and I found some strange behavior. </p> <p>In some cases the scopes appear to work fine without the proc, but not in other cases.</p> <pre><code># models/offer.rb class Offer &lt; ActiveRecord::Base scope :roster, where(:on_roster =&gt; true) scope :commit, where("status_id &gt; 5") end </code></pre> <p>If I use each scope option on independent calls in rails console, the queries are built properly and the results come back as one would have expected in Rails 3.2:</p> <pre><code>$ rails c 2.0.0-p247 :001 &gt; Offer.roster.all.size Offer Load (1.6ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' =&gt; 1 2.0.0-p247 :002 &gt; Offer.commit.all.size Offer Load (1.6ms) SELECT "offers".* FROM "offers" WHERE (status_id &gt; 5) =&gt; 3 </code></pre> <p>However if I chain two scope calls together in the rails console, only the constraints from the last scope in the chain is included in each query:</p> <pre><code>2.0.0-p247 :003 &gt; Offer.roster.commit.all.size Offer Load (1.4ms) SELECT "offers".* FROM "offers" WHERE (status_id &gt; 5) =&gt; 3 2.0.0-p247 :004 &gt; Offer.commit.roster.all.size Offer Load (0.7ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' =&gt; 1 </code></pre> <p>Now if I edit my model to add a proc to the second named scope, like so:</p> <pre><code>class Offer &lt; ActiveRecord::Base scope :roster, where(:on_roster =&gt; true) scope :commit, -&gt; { where("status_id &gt; 5") } end </code></pre> <p>If the named scope with the proc defined is at the end of the chain, it will build the query with both sets of constraints. However, if the named scope without the proc defined is at the end of the chain, the resulting query is built without the constraints of the scope with the proc defined.</p> <pre><code>$ rails c 2.0.0-p247 :003 &gt; Offer.roster.commit.all.size Offer Load (1.4ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' AND (status_id &gt; 5) =&gt; 0 2.0.0-p247 :004 &gt; Offer.commit.roster.all.size Offer Load (0.7ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' =&gt; 1 </code></pre> <p>So the first result is correct, and loads both scopes, but the second is incorrect and only loads the last scope. Then if you change both scopes to use procs, like so:</p> <pre><code># models/offer.rb class Offer &lt; ActiveRecord::Base scope :roster, -&gt; { where(:on_roster =&gt; true) } scope :commit, -&gt; { where("status_id &gt; 5") } end </code></pre> <p>You finally get the expected behavior:</p> <pre><code>$ rails c 2.0.0-p247 :002 &gt; Offer.roster.commit.all.size Offer Load (1.3ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' AND (status_id &gt; 5) =&gt; 0 2.0.0-p247 :001 &gt; Offer.commit.roster.all.size Offer Load (1.7ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' AND (status_id &gt; 5) =&gt; 0 </code></pre> <p>One note on this, <strong>calling <code>reload!</code> in the rails console will not update the behavior</strong> of the scopes after you've updated and saved your model. You have to end your rails console session and begin a new one to get the proc vs. non-proc to pick up correctly.</p> <p>The question I have is how to test to ensure that all of my scopes will behave as expected? Chaining scopes together each time I want to test whether they have a proc or lambda block seems very messy. However the simple tests I set up on the scopes, told me all my scopes were passing, and giving false positive results.</p> <p>Is there an easy way to test via Rspec with Rails4 whether the named scope resides within a proc or lambda block? </p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload