J'ai 2 modèles:Rails N + 1 lorsque vous faites référence au même modèle deux fois
class User < ActiveRecord::Base
end
class Message < ActiveRecord::Base
has_one :sender, :class_name => 'User'
has_one :recipient, :class_name => 'User'
end
et je veux obtenir tous les messages qu'un utilisateur REÇU donc en messages_controller.rb
j'ai:
def messages_to_user
messages = Message.where(recipient_id: current_user.id)
respond_with messages
end
ce service fonctionne, mais dans le journal que je peux voir N + 1 question classique:
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)
donc j'ai essayé de résoudre en ajoutant includes
:
def messages_to_user
messages = Message.includes(:recipient).where(recipient_id: current_user.id)
respond_with messages
end
Mais j'obtiens l'erreur suivante:
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')
Comment il peut être fixé? Je veux retourner une collection de messages - pas un utilisateur et un ensemble de messages à l'intérieur de l'utilisateur. mais sans le N + 1 problème
EDIT
La connexion entre les 2 modèles se fait via la table des messages, voici la migration (champs expéditeur, destinataire), donc j'ai besoin du users.message_id
dans users
. en outre, n'importe quel utilisateur peut envoyer/recevoir plusieurs messages, peut-être que ma mise en œuvre ne reflète pas cela? comment cela devrait-il être fait?
est ici la migration Messages:
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
Eh bien, vous devez ajouter la colonne requise, le message d'erreur est tout à fait clair, il y a un manque 'colonne message_id' sur la table des utilisateurs. – Iceman
@Iceman s'il vous plaît voir mon edit, thatnks. – yossico
Je peux voir que le message d'erreur indique que cette colonne est manquante dans la table des utilisateurs, mais l'utilisateur sinc peut avoir beaucoup de messages je ne peux pas mettre une colonne message_it là. la bonne façon est d'ajouter user_it dans la table des messages, bu alors encore une fois comment puis-je empêcher le n + 1? – yossico