5

Vedo uno strano errore da quando ho spostato da Rails 3.0.11 a 3.1.3. Ecco un codice autonomo per riprodurre l'errore:find_or_initialize_by su has_many associazione causa errore duplicato

require 'active_record' 

ActiveRecord::Base.establish_connection(
    :adapter => 'mysql2', 
    :username => 'root', 
    :database => "some_development" 
) 

class User < ActiveRecord::Base 
    has_many :favorites 
end 

class Favorite < ActiveRecord::Base 
    belongs_to :user 
end 

u = User.create 

# f = u.favorites.find_or_create_by_site_id(123)  #=> pass 
f = u.favorites.find_or_initialize_by_site_id(123) #=> fail 
f.some_attr = 'foo' 
f.save! 

u.name = 'bar' 
u.save!    # ActiveRecord::RecordNotUnique will be thrown here! 

finirà ActiveRecord::RecordNotUnique tentativo di INSERT lo stesso record alla tabella favorites. (Si noti che con questo esempio, la coppia (user_id, site_id) deve essere univoca nei preferiti)

È interessante notare che se utilizzo find_or_create anziché find_or_initialize non vengono generate eccezioni.

Nella traccia dello stack che ho notato autosave_association viene chiamato, non so perché, ma in realtà, invece di has_many :favorites, :autosave => falsehas_many :favorites rimuove l'errore, anche. Come non mi è mai importato di autosave, non sono nemmeno sicuro che se :autosave => false sia una buona idea o meno.

Cosa sto sbagliando o è un bug di Rails? Qualcuno può darmi un puntatore da guardare?

+0

Fa il modello d'uso hanno una convalida per unicità di un campo? Inoltre, qual è la riga commentata con '# => pass' accanto ad essa? Stai cercando di creare due versioni del preferito contemporaneamente o qualcosa del genere? – Batkins

+0

Sì, il modello Utente ha un sacco di convalide inclusa l'unicità, anche se non sono sicuro di come si rapporta. Se commentate la riga di find_or_create invece di find_or_initialize, dovrebbe passare senza errori, come descritto nella mia domanda. – kenn

+0

Puoi provare questo: invece di 'u.save!', Fai 'u.save' e poi' puts u.errors' o 'p u.errors'. Quali sono gli errori. Ho la sensazione che questo è un problema in cui si sta creando un utente che non passa una delle convalide per l'unicità (dal momento che si sta utilizzando un generico 'User.create' senza che vengano immessi attributi). – Batkins

risposta

5

hai provato a non chiamare f.save!? u.save! dovrebbe salvare sia i preferiti che gli utenti.

> f = u.favorites.find_or_initialize_by_site_id(123) 

> u.favorites.include?(f) 
==> false 

> f2 = u.favorites.build(:site_id => 123) 

> u.favorites.include?(f2) 
==> true 

Penso che quello che si trova è che il nuovo favorito f si è creato è un oggetto separato. Quindi salverai f, mentre c'è un altro preferito non salvato anche in u.favourites. Quindi si verifica un errore non univoco quando si salva u (che salva anche i preferiti)

Non sono sicuro se questo è un bug introdotto di recente in Rails 3.1. Potrebbe essere intenzionale.

In Rails 3.0 find_or_initialize_by non compilare la matrice

> f = u.favorites.find_or_initialize_by_site_id(123) 

> u.favorites 
==> [] 

Sembra un insetto - vedi https://github.com/rails/rails/pull/3610

+0

Deve esserci perché "u.save!" Si trova in un punto distante del codice da "f.save!", E c'è la possibilità che "u" non sia sporcato e salti il ​​salvataggio. Voglio sapere il motivo per cui solleva un errore. – kenn