default_scope и ассоциации - PullRequest
       2

default_scope и ассоциации

25 голосов
/ 19 октября 2010

Предположим, у меня есть модель Post и модель Comment.Используя общий шаблон, Post has_many Comments.

Если для Comment установлено значение 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;

Я понимаю базовый принцип удаления с незаданной области всех существующих областей, но не должен ли он знать об этом и сохранять область ассоциации?

Каков наилучший способвытащить ВСЕ комментарии?

Ответы [ 5 ]

16 голосов
/ 09 мая 2012

По некоторым странным причинам

Comment.unscoped { Post.last.comments }

включает default_scope из Comment,

, однако,

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

не не включает default_scope из Comment.

Я испытал это в сеансе rails console с Rails 3.2.3.

9 голосов
/ 21 января 2011

with_exlusive_scope устарело с Rails 3. См. этот коммит .

До (Rails 2):

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

После (Rails 3):

Comment.unscoped { Post.find(post_id).comments }
8 голосов
/ 27 мая 2014

Rails 4.1.1

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

Или

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

Примечание , которое я добавил .scope, похоже, этот блок должен возвращать вид ActiveRecord_AssociationRelation (что .scope делает) не ActiveRecord_Associations_CollectionProxy (без .scope)

6 голосов
/ 17 мая 2013

Это действительно очень неприятная проблема, которая нарушает принцип наименьшего удивления.

Сейчас вы можете просто написать:

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 }
0 голосов
/ 19 октября 2010
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)
...