Загрузка ОДНОЙ записи для has_many и проверка ее - PullRequest
0 голосов
/ 27 октября 2009

Я веду блог с постом и комментариями.

При загрузке сообщения я хочу загружать все голоса текущего пользователя за комментарии к сообщению.

Примерно так (что не работает):

@post.comments.all(:joins => :votes, :conditions => ['votes.user_id = ?', current_user.id])

У каждого комментария есть метод с именем Rating_by?

def rated_by?(actor)
  votes.find_by_user_id(actor.id)
end

Проблема в том, что ActiveRecord будет запускать запрос для каждого рейтингового объекта? позвоните, хотя мой искатель @ post.comments присоединился ко всем соответствующим голосам.

Я посмотрел на плагин act_as_rateable, но у него та же проблема: запуск запроса для каждой записи без использования объединений.

Ответы [ 2 ]

3 голосов
/ 27 октября 2009

Двойной секрет Править: Я отвечал на другой вопрос и наткнулся на то, что должно работать для вас. Это что-то вроде сумасшедшего взлома с использованием глобального хэша Thread.current. И, вероятно, не рекомендуется вообще, но это работает.

Включает создание второй ассоциации голосов has_many в комментариях

class Comment < ActiveRecord::Base
  has_many :votes
  belongs_to :post
  has_many :current_user_votes, :class_name => "Vote",
    :conditions => '`#{Vote.table_name}`.user_id = \
    #{Thread.current[:current_user].id}'
end

Также требуется, чтобы вы установили Thread.current [: current_user] = current_user в контроллере, где вы будете вызывать эти методы.

Тогда вы должны быть в состоянии сделать

@post.comments.find(:all, :include => :current_user_votes) 

Чтобы получить список комментариев, которые уже загружены только: current_user_votes. Все в одном запросе. Если вы получаете несколько сообщений одновременно, вы можете сделать это.

Post.find(:all, :include => { :comments => :current_user_votes},
  :conditions => ...) 

Который будет заполнять список постов и загружать их комментарии, которые, в свою очередь, будут загружать их current_user_votes.

Оригинальный ответ (сохранен для потомков)

Я не думаю, что можно выбрать все из одной модели, чтобы загрузить только соответствующие ассоциации в одном запросе.

Лучшее, что вы получите, это то, что вы сделали. Выберите все из одной модели, а затем для каждой из них загрузите только соответствующую ассоциацию с именованной областью действия или искателем.

Это утверждение, которое не работает, только выбирает комментарии, за которые проголосовал пользователь.

@post.comments.all(:joins => :votes, 
  :conditions => ['votes.user_id = ?', current_user.id])

Этот оператор выбирает тот же набор комментариев, но также активно загружает все голоса за комментарии, которые он выбирает.

@post.comments.all(:include => :votes, 
  :conditions => ['votes.user_id = ?', current_user.id])

В самом деле, что вы собираетесь сделать, это позвонить по адресу Rating_by? на каждый комментарий. Вы можете минимизировать влияние на базу данных, используя именованную область. Но я, честно говоря, не думаю, что это улучшится.

Если вы так беспокоитесь о том, как сильно ударить по базе данных, вы можете сделать что-то вроде этого:

class Post < ActiveRecord::Base
  has_many :comments
  has_many :votes, :through => :comments
  ...
end

class Vote < ActiveRecord::Base
  belongs_to :comments
  ...

  named_scope :made_by_user, lambda {|user| 
    {:conditions => {:user_id => user}}
  }
end

@users_votes = @post.votes.made_by_use(current_user)

@comments = @post.comments.find(:all, :include => :votes)

@comments.each{|comment|
  user_voted_this_on_this_comment = comment.votes & @user_votes
  ...
}

Честно говоря, я не думаю, что это стоит усилий.

P.S. Существует соглашение Ruby относительно имен методов, которые заканчиваются знаком вопроса, всегда должны возвращать логическое значение.

1 голос
/ 27 октября 2009

вам нужно использовать

:include => :votes

объединения не загружают ваши данные, они просто присоединяются к запросу в БД.

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