default_scope and associations

前端 未结 6 1572
猫巷女王i
猫巷女王i 2020-12-06 04:17

Suppose I have a Post model, and a Comment model. Using a common pattern, Post has_many Comments.

If Comment has a default_scope set:

default_scope w         


        
相关标签:
6条回答
  • 2020-12-06 05:01

    How about this?

    # Use this scope by default
    scope :active, -> { where(deleted_at: nil) }
    
    # Use this whenever you want to include all comments regardless of their `deleted_at` value
    scope :with_soft_deleted, -> { unscope(where: :deleted_at)
    
    default_scope, -> { active }
    

    post.comments would fire this query:

    SELECT "comments".* FROM "comments" WHERE "comments"."deleted_at" IS NULL AND "comments"."post_id" = $1;
    

    post.comments.with_soft_deleted would send this:

    SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = $1;
    
    0 讨论(0)
  • 2020-12-06 05:02

    Rails 4.1.1

    Comment.unscope(where: :deleted_at) { Post.first.comments }
    

    Or

    Comment.unscoped { Post.first.comments.scope }
    

    Note that I added .scope, it seems like this block should return kind of ActiveRecord_AssociationRelation (what .scope does) not ActiveRecord_Associations_CollectionProxy (without a .scope)

    0 讨论(0)
  • 2020-12-06 05:07
    class Comment
      def post_comments(post_id)
        with_exclusive_scope { find(all, :conditions => {:post_id => post_id}) }
      end
    end
    
    Comment.post_comments(Post.first.id)
    
    0 讨论(0)
  • For some strange reasons,

    Comment.unscoped { Post.last.comments }
    

    includes the default_scope of Comment,

    however,

    Comment.unscoped { Post.last.comments.to_a }
    Comment.unscoped { Post.last.comments.order }
    

    do not include the default_scope of Comment.

    I experienced this in a rails console session with Rails 3.2.3.

    0 讨论(0)
  • 2020-12-06 05:13

    with_exlusive_scope is deprecated as of Rails 3. See this commit.

    Before (Rails 2):

    Comment.with_exclusive_scope { Post.find(post_id).comments }
    

    After (Rails 3):

    Comment.unscoped { Post.find(post_id).comments }
    
    0 讨论(0)
  • 2020-12-06 05:19

    This is indeed a very frustrating problem which violates the principle of least surprise.

    For now, you can just write:

    Comment.unscoped.where(post_id: Post.first)
    

    This is the most elegant/simple solution IMO.

    Or:

    Post.first.comments.scoped.tap { |rel| rel.default_scoped = false }
    

    The advantage of the latter:

    class Comment < ActiveRecord::Base
      # ...
    
      def self.with_deleted
        scoped.tap { |rel| rel.default_scoped = false }
      end
    end
    

    Then you can make fun things:

    Post.first.comments.with_deleted.order('created_at DESC')
    

    Since Rails 4, Model.all returns an ActiveRecord::Relation , rather than an array of records. So you can (and should) use all instead of scoped:

    Post.first.comments.all.tap { |rel| rel.default_scoped = false }
    
    0 讨论(0)
提交回复
热议问题