This project is archived and is in readonly mode.

#5386 ✓stale
Akira Matsuda

AR::Base#unscoped inconsistency

Reported by Akira Matsuda | August 16th, 2010 @ 10:15 AM | in 3.1

AR::Base#unscoped shows strange behaviour.
In short, it works unexpectedly on default_scoped model only when called via method chaining and chains to another named_scope.

Let me show an example. Consider the following model:

% rails g model post title:string body:string author:string published:boolean
class Post < ActiveRecord::Base
  default_scope where :published => true
  scope :written_by, lambda {|name| where :author => name}
end

Queries are default_scoped like this:

Post.scoped.to_sql
=> SELECT     "posts". FROM       "posts"  WHERE     ("posts"."published" = 't')
Post.written_by('DHH').to_sql
=> SELECT     "posts". FROM       "posts"  WHERE     ("posts"."published" = 't') AND ("posts"."author" = 'DHH')

and unscoped method works as documented:

Post.unscoped.to_sql
=> SELECT     "posts".* FROM       "posts"

unscoped + where unscopes the default_scope and adds the where conditions:

Post.unscoped.where(:author => 'DHH').to_sql
=> SELECT     "posts".* FROM       "posts"  WHERE     ("posts"."author" = 'DHH')

it works the same with a named_scope given inside a block:

Post.unscoped { Post.written_by 'DHH' }.to_sql
=> SELECT     "posts".* FROM       "posts"  WHERE     ("posts"."author" = 'DHH')

BUT, the unscoped default_scope comes back to life while unscoped are combined with a named_scope via method chaining.

Post.unscoped.written_by('DHH').to_sql
=> SELECT     "posts".* FROM       "posts"  WHERE     ("posts"."published" = 't') AND ("posts"."author" = 'DHH')

Is this intentional or a bug?

Comments and changes to this ticket

  • Neeraj Singh

    Neeraj Singh August 16th, 2010 @ 02:26 PM

    • Milestone set to 3.x
    • State changed from “new” to “open”
    • Importance changed from “” to “Low”

    Yes it is a bug.

  • Neeraj Singh

    Neeraj Singh August 16th, 2010 @ 02:48 PM

    I personally think a design change is needed to fix this issue. In the meantime following code will solve the issue.

        Post.unscoped do
          self.written_by('dhh').to_sql
        end
    
  • Cyrille

    Cyrille September 2nd, 2010 @ 12:14 PM

    Moreover:

    class Organization < ActiveRecord::Base
    
      default_scope where("organizations.state = 'active'").order("organizations.qs DESC, organizations.title ASC")
    
      unscoped do
        scope :latest, lambda { |num| order("organizations.created_at DESC").where("organizations.state = 'active'").limit(num) }
      end
    
      def self.latest2(num)
        unscoped.order("organizations.created_at DESC").where("organizations.state = 'active'").limit(num) 
      end
    
    end
    

    ruby-1.9.2-p0 > Organization.latest(5).to_sql
    => "SELECT organizations.* FROM organizations WHERE (organizations.state = 'active') ORDER BY organizations.qs DESC, organizations.title ASC, organizations.created_at DESC LIMIT 5"

    if the named scope is defined inside the unscoped block it's not working. Whereas the following is working as excepted

    ruby-1.9.2-p0 > Organization.latest2(5).to_sql
    => "SELECT organizations.* FROM organizations WHERE (organizations.state = 'active') ORDER BY organizations.created_at DESC LIMIT 5"

  • Neeraj Singh

    Neeraj Singh September 3rd, 2010 @ 06:34 PM

    • Assigned user set to “Neeraj Singh”

    @Cyrille Personally I think latest is working as expected. The latest scope should not be declared inside unscoped.

    I will take another look at this defect but as I remember from my first stab at this issue it is kind of hard to fix without some design change. However now that rails2 is released I will look into it with the possibility of some change in design.

  • Cyrille

    Cyrille September 11th, 2010 @ 09:31 AM

    @Neeraj

    In rails 2 I think you were allowed to do stuff like

       with_exclusive_scope do
        named_scope :most_recent ...
        named_scope :cheapest ...
       end
    

    In order to define all named scope that don't require default_scope

    So I was wondering what's the equivalent in Rails 3 as you said it's not unscoped do ?

    The only way for now I find in order to defined scope that wouldn't apply default_scope is to create class method for them like my previous latest2 example. I just think with_exclusive_scope was DRYer ;)

  • Neeraj Singh
  • Santiago Pastorino

    Santiago Pastorino November 7th, 2010 @ 11:35 AM

    • Milestone changed from 3.x to 3.1
    • Assigned user changed from “Neeraj Singh” to “Aaron Patterson”
  • rails

    rails March 29th, 2011 @ 01:00 AM

    This issue has been automatically marked as stale because it has not been commented on for at least three months.

    The resources of the Rails core team are limited, and so we are asking for your help. If you can still reproduce this error on the 3-0-stable branch or on master, please reply with all of the information you have about it and add "[state:open]" to your comment. This will reopen the ticket for review. Likewise, if you feel that this is a very important feature for Rails to include, please reply with your explanation so we can consider it.

    Thank you for all your contributions, and we hope you will understand this step to focus our efforts where they are most helpful.

  • rails

    rails March 29th, 2011 @ 01:00 AM

    • State changed from “open” to “stale”
  • Brian Bokor

    Brian Bokor April 26th, 2011 @ 11:59 PM

    I dont' have a solution for this issue but I have noticed that in 3.0.5

    Doesn't work
    scope :latest, unscoped.order()

    Doesn't work
    unscoped do

     scope :latest, order()
    

    end

    Works
    def self.latest

    unscoped.order()
    

    end

    Works (although deprecated)
    scope :latest, reorder()

    I'm not sure I'll have time right now to look into fixing but that is what my tests have proven.

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Referenced by

Pages