1

ユーザー、投稿、コメントを含むアプリケーションがあります。ユーザーhas_many投稿、投稿has_manyコメントおよびコメントbelong_toユーザーおよび投稿。

私のビューテンプレートでは、コメント投稿者のユーザー名を取得するために、次のようなコメントをループしています。

User.find(comment.user_id).name

投稿ごとのコメントごとにこれを行う場合、これはどのくらい効率的ですか?コメントテーブルの別の行にユーザー名を格納する方が速いかもしれないと想像できますが、データを複製するのは間違っているようです。

私は妄想的で、ActiveRecordはキャッシュの魔法を使っていますか、それともこのようなことをするより良い方法がありますか?

4

4 に答える 4

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
于 2012-07-04T09:29:44.847 に答える
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
于 2012-07-04T09:30:17.837 に答える
0

アソシエーションの積極的な読み込み

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
于 2012-07-04T09:28:25.917 に答える
0

パフォーマンスが問題になる場合は、Mongodbのような非リレーショナルDBを使用するのが最善の方法です。

それでもActiveRecordを使用したい場合は、Post.comments.include(:user)(未使用のユーザー情報をロードする)で熱心なロードを使用するか、キャッシュ技術を使用できます。

user.name発生する可能性のある変更を制御する限り、提案したように、コメントテーブルにをキャッシュしても問題ありません。Userモデルにコールバックを設定することで、これを行うことができます。

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

この手法は一種のDBキャッシングですが、もちろん、HTMLフラグメントをキャッシュすることもできます。また、コメントブロックはHTMLブロックをキャッシュするのに適しています。

于 2012-07-04T10:11:44.340 に答える