Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

with_exclusive_scope does not override the default_scope when each provides IS NULL / IS NOT NULL conditions

#3838
class Page < ActiveRecord::Base
  default_scope where(:deleted_at => nil)

  def self.deleted
    with_exclusive_scope :find => where('pages.deleted_at IS NOT NULL') do
      self
    end
  end
end

Page.all emits this SQL:

SELECT "pages".* FROM "pages" WHERE ("pages"."deleted_at" IS NULL)

While Page.deleted.all emits this:

SELECT "pages".* FROM "pages" WHERE ("pages"."deleted_at" IS NULL) AND ("pages"."deleted_at" IS NOT NULL)

Attached is a failing test.

Reported by foca · February 1st, 2010 @ 10:36 PM

State: resolved
Milestone: 3.0.2
Assigned to: José Valim José Valim
Importance: Low

Activity

  1. José Valim
    José Valim
    • Assigned user set to Pratik
    • Milestone cleared.

    February 3rd, 2010 @ 10:08 AM

  2. Neeraj Singh
    Neeraj Singh
    • Tag changed from activerecord, rails3 to activerecord, patch, rails3
    • Assigned user changed from Pratik to José Valim
    • State changed from new to open
    • Importance changed from to Low

    Attached is code patch and test as discussed with José Valim.

    June 28th, 2010 @ 10:22 PM

  3. Repository
    Repository
    • State changed from open to resolved

    (from [40e87ac66912b06c31c98b057a49c64f5555dd99]) with_exclusive_scope does not work properly if ARel is passed. It does work nicely if hash is passed. Blow up if user is attempting it pass ARel to with_exclusive_scope.

    [#3838 with_exclusive_scope does not override the default_scope when each provides I... state:resolved]

    Signed-off-by: José Valim jose.valim@gmail.com
    http://github.com/rails/rails/commit/40e87ac66912b06c31c98b057a49c6...

    June 29th, 2010 @ 12:18 AM

  4. Pratik
    Pratik
    • State changed from resolved to open

    How is the issue originally raised by foca is related to the new finder syntax and the commit above ?

    The below would have the same issue.

    class Page < ActiveRecord::Base
      default_scope :conditions => {:deleted_at => nil}
    
      def self.deleted
        with_exclusive_scope :find => where('pages.deleted_at IS NOT NULL') do
          self
        end
      end
    end
    

    June 29th, 2010 @ 12:46 AM

  5. Neeraj Singh
    Neeraj Singh

    The commit above will make the code blow up. This ensures that you are not getting the wrong result.

    Above code will blow up with following message.

    ARel can not be used with_exclusive_scope. You can either specify hash style conditions to with_exclusive_scope like this:
                  
    User.with_exclusive_scope {:find => :conditions => {:active => true} } do
    end
    
    Or you can use unscoped method instead of with_exclusive_scope like this:
                  
    User.unscoped.where(:active => true) do
    end
    

    The fix is not ideal. However I am not able to find a decent way to fix this without changing the fundamental way how default_scope is currently applied.

    Ideally the arel returned should not have default_scope applied and the default_scope should be applied at the very end and not at the very beginning which is the case right now.

    June 29th, 2010 @ 02:16 AM

  6. José Valim
    José Valim

    Pratik, the reason why his code is failing is because when you call where('pages.deleted_at IS NOT NULL'), it's still outside the with_exclusive_scope method and consequently this new relation is created on top of the default_scope.

    That said, the with_exclusive_scope syntax cannot work with relations. This is not due to how with_exclusive_scope works, but how relations are created. So we chose to raise a warning if the user gives a relation to with_exlusice_scope, telling him to use unscoped instead. Which is simpler and works as well.

    Notice that, if you give hash conditions, it would work (as Neeraj said):

    User.with_exclusive_scope {:find => :conditions => {:active => true} } do
    end
    

    And I think moving from with_exclusive_scope to unscoped is a good change, because it's a simpler syntax (as you moved most of ActiveRecord internals to use it as well instead of with_exclusive_scope).

    June 29th, 2010 @ 09:08 AM

  7. José Valim
    José Valim

    Just one note, in Neeraj comment above, you don't need to pass a block to where (that syntax does not work). The correct is just to call unscoped:

    User.unscoped.where(:active => true)
    

    June 29th, 2010 @ 11:03 AM

  8. José Valim
    José Valim
    • State changed from open to resolved

    June 29th, 2010 @ 04:45 PM

  9. Jeremy Kemper
  10. Jeff Kreeftmeijer
    Jeff Kreeftmeijer
    • Tag cleared.

    Automatic cleanup of spam.

    November 8th, 2010 @ 08:51 AM

  11. bingbing
  12. bingbing
  13. bingbing
  14. bingbing