26

Post モデルと Comment モデルがあるとします。一般的なパターンを使用して、has_many コメントを投稿します。

コメントに default_scope が設定されている場合:

default_scope where("deleted_at IS NULL")

スコープに関係なく、投稿のすべてのコメントを簡単に取得するにはどうすればよいですか? これにより、無効な結果が生成されます。

Post.first.comments.unscoped

次のクエリが生成されます。

SELECT * FROM posts LIMIT 1;
SELECT * FROM comments;

それ以外の:

SELECT * FROM posts LIMIT 1;
SELECT * FROM comments WHERE post_id = 1;

ランニング:

Post.first.comments

プロデュース:

SELECT * FROM posts LIMIT 1;
SELECT * FROM comments WHERE deleted_at IS NULL AND post_id = 1;

既存のすべてのスコープを削除するスコープなしの基本原則は理解していますが、関連スコープを認識して保持する必要はありませんか?

すべてのコメントを取得する最良の方法は何ですか?

4

6 に答える 6

9

with_exlusive_scopeRails 3の時点で非推奨です。このコミットを参照してください。

前(Rails 2):

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

後(Rails 3):

Comment.unscoped { Post.find(post_id).comments }
于 2011-01-21T13:22:20.563 に答える
8

Rails 4.1.1

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

または

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

私が追加したことに.scope注意ActiveRecord_AssociationRelationて ください。.scopeActiveRecord_Associations_CollectionProxy.scope

于 2014-05-27T10:15:07.213 に答える
6

これは確かに、最小の驚きの原則に違反する非常に苛立たしい問題です。

今のところ、次のように書くことができます:

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

これは、IMO で最もエレガントでシンプルなソリューションです。

または:

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

後者の利点:

class Comment < ActiveRecord::Base
  # ...

  def self.with_deleted
    scoped.tap { |rel| rel.default_scoped = false }
  end
end

次に、楽しいものを作成できます。

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

Rails 4 以降、 Model.all はレコードの配列ではなく ActiveRecord::Relation を返します。allしたがって、次の代わりに使用できます(そして使用する必要があります)scoped

Post.first.comments.all.tap { |rel| rel.default_scoped = false }
于 2013-05-17T18:21:01.053 に答える
0
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)
于 2010-10-19T06:06:19.373 に答える