2017-01-22 5 views
0

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 
+0

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

+0

@Iceman s'il vous plaît voir mon edit, thatnks. – yossico

+0

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

Répondre

1

Essayez

messages = Message.includes(:recipient).references(:recipient).where(recipient_id: current_user.id)