0
を参照するときに、私は2つのモデルがあります:RailsのN + 1回、同じモデルに
class User < ActiveRecord::Base
end
class Message < ActiveRecord::Base
has_one :sender, :class_name => 'User'
has_one :recipient, :class_name => 'User'
end
を、私は私が持っているユーザーはmessages_controller.rb
にして受け取ったすべてのメッセージを取得したい:
def messages_to_user
messages = Message.where(recipient_id: current_user.id)
respond_with messages
end
このサービスは動作しますが、ログに私は古典的なN + 1つの問題を見ることができます:
Started GET "/messages_to_user" for 127.0.0.1 at 2017-01-22 15:35:01 +0200
Processing by MessageController#user as */*
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 2]]
Message Load (0.0ms) SELECT "messages".* FROM "messages" WHERE "messages"."recipient_id" = ? [["recipient_id", 2]]
[active_model_serializers] User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModelSerializers::Adapter::Attributes (42.01ms)
Completed 200 OK in 217ms (Views: 63.0ms | ActiveRecord: 3.0ms)
は、だから私はを追加することによって、それを解決しようとしました:
def messages_to_user
messages = Message.includes(:recipient).where(recipient_id: current_user.id)
respond_with messages
end
しかし、その後、私は次のエラーを取得する:それは固定することができますどのように
SQLite3::SQLException: no such column: users.message_id: SELECT "users".* FROM "users" WHERE "users"."message_id" IN ('1', '2', '3', '4', '5', '6', '7', '8', '9')
? 私は、ユーザとユーザ内のメッセージセットではなく、メッセージの集合を返したいと思います。しかし、N + 1問題なく
EDIT
2つのモデル間の接続は、メッセージテーブルを介して行われ、ここでの移行(フィールドの送信者、受信者が)あるので、私はusers
でusers.message_id
を必要といけません。さらに、どのユーザも複数のメッセージを送受信することができますが、私の実装はそれを反映していませんか?どのようにそれを行う必要がありますか?ここ
は、メッセージの移行です:
class CreateMessages < ActiveRecord::Migration
def change
create_table :messasges do |t|
t.string :title
t.references :sender, index: true, foreign_key: true
t.references :recipient, index: true, foreign_key: true
t.string :content
t.timestamps null: false
end
end
end
を試してみて、エラーメッセージは非常に明確である、上の欠落している 'message_id'列がありますusersテーブル – Iceman
@Iceman私の編集、thatnksをご覧ください。 – yossico
私は、この列がユーザーの表にはありませんが、sincユーザーはメッセージの列を置くことができない多くのメッセージを持つことができるというエラーメッセージが表示されていることがわかります。正しい方法は、メッセージテーブルにuser_itを追加することです。その後buを再実行して、どのようにn + 1を防ぐことができますか? – yossico