2016-07-17 161 views
8

Ho un modello di database come questo:ActiveRecord unisce condizione di soddisfare tutti i rapporti

Post 
    has_many :votes 
    belongs_to :user 
User 
    has_many :posts 
    has_many :votes 
Vote 
    belongs_to :post 
    belongs_to :user 

Quello che voglio è richiesta tutta posts per un utente specifico che non ha votato per già.

Ho provato così:

Post.left_outer_joins(:votes).where.not(votes: { user_id: 1 }) 

dove 1 è solo un esempio id utente.

Il problema è che questa query sembra recuperare tutte le posts che hanno almeno un voto in cui lo user_id non è 1.
Ma poiché più di un utente voterà per questi post, una volta che ci sono più di un voto, tutti gli utenti riceveranno tutti i messaggi in questo momento.

non so se joins è l'approccio giusto ma in inglese il mio Query sarebbe:

Dammi tutti i post nessuno dei voti hanno un'user_id di 1

Is è possibile recuperare solo il posts per un utente che non ha già votato?

EDIT:

mio schema del database dei suddetti tre tabelle:

Voti:

CREATE TABLE "votes" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
     "post_id" integer, 
     "user_id" integer, 
     "created_at" datetime NOT NULL, 
     "updated_at" datetime NOT NULL, 
     "vote_type" integer DEFAULT 0); 
CREATE INDEX "index_votes_on_post_id" ON "votes" ("post_id"); 
CREATE INDEX "index_votes_on_user_id" ON "votes" ("user_id"); 

Messaggi:

CREATE TABLE "posts" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
     "photo_gcs_key" varchar, "photo_gcs_bucket" varchar, 
     "user_id" integer, "campaign_id" integer, 
     "created_at" datetime NOT NULL, 
     "updated_at" datetime NOT NULL); 
CREATE INDEX "index_images_on_user_id" ON "images" ("user_id"); 
CREATE INDEX "index_images_on_campaign_id" ON "images" ("campaign_id"); 

Utenti:

CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
     "uid" varchar, "display_name" varchar, "email" varchar, 
     "photo_url" varchar, "photo_gcs_key" varchar, 
     "photo_gcs_bucket" varchar, "user_name" varchar, 
     "created_at" datetime NOT NULL, 
     "updated_at" datetime NOT NULL); 
+0

Potresti per favore pubblicare lo schema dei tre tavoli precedenti? – 1000111

+0

@ 1000111 Cosa intendi? Le prime righe mostrano le relazioni tra i tavoli. Cos'altro ti serve? – Ybrin

+0

incolla l'output di questa query: 'mostra crea tabella ' – 1000111

risposta

8

Quindi, se non si cura di ignorare i messaggi che vengono creati dall'utente, dovrebbe essere qualcosa di simile

Scopri quali messaggi l'utente ha votato prima, poi quelle non ritenute.

Post.where.not(id: Vote.where(user_id: user_id).select(:post_id)) 
1

Ho impostato un esempio come quello che hai descritto. Ho creato un utente, id '1' e cinque post, id '1' - '5'. Poi ho creato Mi piace per i post "2" e "4". La sintassi nell'altra risposta non ha funzionato, si lamentava dello not. I seguenti lavori per selezionare i post (1, 3, 5) che non sono stati graditi dall'utente '1'

irb(main):062:0> Post.where(Sequel.~(id: Vote.select(:post_id).where(user_id: 1))) 
=> #<Sequel::MySQL::Dataset: "SELECT * FROM `posts` WHERE (`id` NOT IN (SELECT `post_id` FROM `votes` WHERE (`user_id` = 1)))"> 

irb(main):063:0> Post.where(Sequel.~(id: Vote.select(:post_id).where(user_id: 1))).all 
=> [#<Post @values={:id=>1, :photo_gcs_key=>nil, :photo_gcs_bucket=>nil, :user_id=>1, :campaign_id=>nil, :created_at=>2016-08-12 17:23:53 -0700, :updated_at=>2016-08-12 17:23:53 -0700}>, #<Post @values={:id=>3, :photo_gcs_key=>nil, :photo_gcs_bucket=>nil, :user_id=>1, :campaign_id=>nil, :created_at=>2016-08-12 17:23:56 -0700, :updated_at=>2016-08-12 17:23:56 -0700}>, #<Post @values={:id=>5, :photo_gcs_key=>nil, :photo_gcs_bucket=>nil, :user_id=>1, :campaign_id=>nil, :created_at=>2016-08-12 17:23:57 -0700, :updated_at=>2016-08-12 17:23:57 -0700}>] 
+0

Oops, la mia risposta non è un'impostazione di ActiveRecord, è una configurazione del modello Sequel Ruby. – Tony

Problemi correlati