Rails 3: has_many: проблема uniq - PullRequest
2 голосов
/ 07 марта 2011

Вот пример настройки модели (barebone Rails 3.0.5):

class Post < ActiveRecord::Base  
  has_many :comments
end

class Comment < ActiveRecord::Base  
  belongs_to :post
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :comments
  has_many :commented_posts, through: :comments, source: :post, uniq: true
end

Теперь следующее работает правильно:

ruby-1.9.2-p0 > user.commented_posts.count
  SQL (0.2ms)  SELECT COUNT(DISTINCT "posts".id) FROM "posts" INNER JOIN "comments" ON "posts".id = "comments".post_id WHERE (("comments".user_id = 1))
=> 1

Но добавление условия делает активную запись «забытой»о uniq: true бит:

ruby-1.9.2-p0 > user.commented_posts.where("posts.id != 42").count
  SQL (0.2ms)  SELECT COUNT(*) FROM "posts" INNER JOIN "comments" ON "posts".id = "comments".post_id WHERE (("comments".user_id = 1)) AND (posts.id != 42)
=> 2

Ошибка?Или что мне не хватает?

редактировать:

all работает:

ruby-1.9.2-p0 > user.commented_posts.where("posts.id != 42").all
  Post Load (0.3ms)  SELECT DISTINCT "posts".* FROM "posts" INNER JOIN "comments" ON "posts".id = "comments".post_id WHERE (("comments".user_id = 1)) AND (posts.id != 42)
=> [#<Post id: 1, created_at: "2011-03-07 12:17:30", updated_at: "2011-03-07 12:17:30">] 

явно uniq тоже:

ruby-1.9.2-p0 > user.commented_posts.where("posts.id != 42").uniq.count
  Post Load (0.2ms)  SELECT DISTINCT "posts".* FROM "posts" INNER JOIN "comments" ON "posts".id = "comments".post_id WHERE (("comments".user_id = 1)) AND (posts.id != 42)
=> 1

edit 2

Действительно ошибка в Rails.Я представил патч.Пожалуйста, проголосуйте, чтобы он прошел быстрее.https://github.com/rails/rails/pull/2924#issuecomment-3317185

Ответы [ 2 ]

1 голос
/ 18 августа 2011

Я столкнулся с этим на 3.0.9 и 3.0.10.Я считаю это ошибкой верблюда, хотя может быть какая-то причина, по которой он так себя ведет.

Я пытался переопределить счетчик метода объединения ...

has_many :commented_posts, through: :comments, source: :post, uniq: true do
  def count(column_name = nil, opts = {})
    super(column_name || 'users.id', opts.reverse_merge(distinct: true))
  end
end

Но арель игнорируетметод подсчета, если условие присутствует.Вот почему я думаю, что это ошибка.

В качестве хакерского решения я использую @ comments.count ('users.id', different: true), чтобы заставить поведение вести себя в ситуациях, когда @comments можетесть условие, прикрепленное к контроллеру.

0 голосов
/ 01 апреля 2011

Я думаю, что явный uniq вызывает счет в массиве в памяти, а не в базе данных. Вы можете сказать, что это верно из SELECT DISTINCT, а не из SELECT COUNT DISTINCT. Это вытянет все записи из БД в рельсы, а затем подсчитает их.

Можно заставить БД сделать это, передав пару параметров для подсчета

collection.count (: id,: Different => true) приведет к созданию правильного кода SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...