come aggiungere record a has_many: tramite associazione in rails


94
class Agents << ActiveRecord::Base
  belongs_to :customer
  belongs_to :house
end

class Customer << ActiveRecord::Base
  has_many :agents
  has_many :houses, through: :agents
end

class House << ActiveRecord::Base
  has_many :agents
  has_many :customers, through: :agents
end

Come aggiungo al Agentsmodello perCustomer ?

È questo il modo migliore?

Customer.find(1).agents.create(customer_id: 1, house_id: 1)

Quanto sopra funziona bene dalla console, tuttavia, non so come ottenerlo nell'applicazione reale.

Immagina che venga compilato un modulo per il cliente che prende anche house_idcome input. Quindi faccio quanto segue nel mio controller?

def create 
  @customer = Customer.new(params[:customer])
  @customer.agents.create(customer_id: @customer.id, house_id: params[:house_id])
  @customer.save
end

Nel complesso sono confuso su come aggiungere record nella has_many :throughtabella?


In quale controller memorizzereste la funzione "crea"?
Tobias Kolb

Risposte:


163

Penso che tu possa semplicemente fare questo:

 @cust = Customer.new(params[:customer])
 @cust.houses << House.find(params[:house_id])

O quando si crea una nuova casa per un cliente:

 @cust = Customer.new(params[:customer])
 @cust.houses.create(params[:house])

Puoi anche aggiungere tramite ID:

@cust.house_ids << House.find(params[:house_id])

16
FYI: non puoi creare la casa associata a meno che il genitore non sia già salvato.
Ricardo Otero

Questa deve essere la soluzione più elegante a questo problema che ho incontrato. +1 per te.
Daniel Bonnell,

@RicardoOtero immagino che possiamo usare buildinvece di create?
Karan

@Mischa come dovrei gestire l'errore se House.find (params [: house_id]) è nullo .. ho ricevuto un errore di TypeMismatch se params [: house_id] è nullo .. sto già usando rescue. ma c'è un modo migliore .. ??
Vishal

1
Ho osservato che l'uso di <<operator fa l'inserimento due volte in alcuni casi. Quindi il createmetodo è il modo migliore.
Scambia il

77

"Il modo migliore" dipende dalle tue esigenze e da ciò che ti sembra più comodo. La confusione deriva dalle differenze di comportamento ActiveRecord del newe createmetodi e l' <<operatore.

Il newmetodo

newnon aggiungerà un record di associazione per te. Devi creare Housee Agentregistrare da solo:

house = @cust.houses.new(params[:house])
house.save
agent = Agent(customer_id: @cust.id, house_id: house.id)
agent.save

Nota che @cust.houses.newe House.newsono effettivamente gli stessi perché devi creare il Agentrecord in entrambi i casi.

L' <<operatore

Come menzionato da Mischa, puoi anche utilizzare l' <<operatore sulla raccolta. Questo costruirà solo il Agentmodello per te, devi costruire il Housemodello:

house = House.create(params[:house])
@cust.houses << house
agent = @cust.houses.find(house.id)

Il createmetodo

createcostruirà sia Housee Agentrecord per voi, ma è necessario trovare il Agentmodello di se avete intenzione di tornare che alla vista o di api:

house = @cust.houses.create(params[:house])
agent = @cust.agents.where(house: house.id).first

Come nota finale, se vuoi che le eccezioni vengano sollevate durante la creazione, houseusa invece gli operatori bang (ad esempio new!e create!).


2
La riga dovrebbe invece agent = @cust.houses.find(house.id)leggere agent = @cust.agents.find(house.id)? La agentvariabile nel "nuovo metodo" è diversa da quella agentnegli ultimi esempi. Potrebbe creare un po 'di confusione per le persone che lavorano con attributi aggiuntivi nella tabella di join.
Vaughan

puoi approfondire il recupero dei dati dalla tabella congiunta Agenti senza avere N + 1 bug di esempio che mostra tutte le case e gli agenti corrispondenti per il dato cliente
Ankita.P

6

Un altro modo per aggiungere associazioni è utilizzare le colonne della chiave esterna:

agent = Agent.new(...)
agent.house = House.find(...)
agent.customer = Customer.find(...)
agent.save

Oppure utilizza i nomi esatti delle colonne, passando l'ID del record associato invece del record.

agent.house_id = house.id
agent.customer_id = customer.id
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.