default_scope and associations

被刻印的时光 ゝ 提交于 2019-11-27 22:44:53

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.

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 }

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)

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 }
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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!