2012-07-04 3 views
1

У меня есть приложение с пользователями, сообщениями и комментариями. Пользователи has_many Posts, Posts has_many Комментарии и комментарии принадлежат пользователям и сообщениям.Эффективность Rails при поиске ассоциаций

В моем шаблоне вида я зацикливание над Комментарии, как это, чтобы получить имя пользователя комментатора:

User.find(comment.user_id).name

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

Я являюсь параноиком и является ActiveRecord, делающим магию кеширования, или есть лучший способ сделать что-то подобное?

ответ

0

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

Предположим, у вас есть метод контроллера:

def show 
    @posts = Post.limit(10).includes(:comments => :user) 
end 

на ваш взгляд, как вы перебираем @comments:

@posts.each do |post| 
    # show post stuff 
    post.comments.each do |comment| 
    comment.user.name 
    end 
end 
+0

поэтому, если я ограничу сообщения, возвращаемые (скажем, 10), '@ comments' будет только захватывать пользователей для 10 возвращенных сообщений? – DeanAlexRainier

+0

@daanVOS Я обновил свой пример. Это загружает десять сообщений и включает комментарии и комментарии пользователя с нетерпением. – lebreeze

+0

@daanVOS таким образом, приложение, скорее всего, сделает один SQL-запрос для сообщений, один для комментариев и один для пользователей, которые сделали эти комментарии, независимо от количества комментариев. – lebreeze

0

Eager loading of associations

class Post < ActiveRecord::Base 
    has_many :comments 
    # ... 
end 

class Comment < ActiveRecord::Base 
    belongs_to :user 
end 


comments = @post.comments.includes(:user) 

Это подожмет пользователь.

SQL будет выглядеть следующим образом:

SELECT * FROM `comments` WHERE `comments`.`post_id` = 42; 
SELECT * FROM `users` WHERE `users`.`id` IN (1,2,3,4,5,6) # 1,2,3,4,5,6 - user_ids from comments 
+0

, но тогда я должен сделать еще один запрос, чтобы получить сообщения ... – DeanAlexRainier

+0

Вы хотите что-нибудь написать с комментариями пользователей с сообщениями пользователей? – cutalion

0

Пересмотренный

Если у вас есть связь, как показано ниже вы можете получить доступ к пользователю от комментариев сам объект comment.user

class User < ActiveRecord::Base 
    has_many :posts 
    has_many :comments 
end 

class Post < ActiveRecord::Base 
    belongs_to :user 
    has_many :comments 
end 

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

Разве это не означает, что пользователь комментариев совпадает с владельцем сообщения, связанного с комментарием? В этом случае это было бы совершенно неправильно, так как многие пользователи могут прокомментировать сообщение другого пользователя? – lebreeze

+0

@lebreeze, у меня тот же вопрос – cutalion

+0

Позвольте мне исправить ... – Bongs

0

Если производительность является проблемой для вас, используя не реляционную БД, как Mongodb - это путь.

Если вы все еще хотите использовать ActiveRecord, либо использовать жадную загрузку с Post.comments.include(:user) (который загрузит неиспользуемые пользователь информацию - и это не большое), или вы можете использовать кэширования техники.

Я нахожу это в порядке, чтобы кэшировать user.name в таблице комментариев, как вы предполагали, до тех пор, пока вы контролируете изменения, которые могут произойти. Вы можете сделать это путем установки обратных вызовов в вашей User модели:

after_save do |user| 
    Comment.where(user_id: user.id).update_all(:username, user.name) 
end 

Этот метод является своего рода кэширование БД, но, конечно же, вы можете кэшировать фрагменты HTML. Блок комментариев - это хороший способ кэшировать блок HTML.

Смежные вопросы