5

Veo un error extraño desde que cambié de Rails 3.0.11 a 3.1.3. Aquí hay un código independiente para reproducir el error:find_or_initialize_by en la asociación has_many provoca un error duplicado

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! 

terminará ActiveRecord::RecordNotUnique intentar INSERT el mismo registro a la tabla favorites. (Tenga en cuenta que con este ejemplo, (user_id, site_id) par debe ser único en favoritos)

Curiosamente, si uso find_or_create en lugar de find_or_initialize no hay excepciones son criados.

En el seguimiento de la pila noté que se llama autosave_association, no sé por qué, pero en realidad has_many :favorites, :autosave => false en lugar de has_many :favorites también elimina el error. Como nunca me ha importado autosave, ni siquiera estoy seguro de si :autosave => false es una buena idea o no.

¿Qué estoy haciendo mal, o es un error de Rails? ¿Alguien puede darme un puntero para mirar?

+0

¿El modelo de usuario tienen una validación para la unicidad de un campo? Además, ¿qué es esa línea comentada con '# => pass' junto a ella? ¿Estás tratando de crear dos versiones de favoritos a la vez o algo así? – Batkins

+0

Sí, el modelo de usuario tiene un montón de validaciones, incluida la exclusividad, aunque no estoy seguro de cómo se relaciona. Si hace un comentario, en la línea de find_or_create en lugar de find_or_initialize, debería pasar sin error, como se describe en mi pregunta. – kenn

+0

Puedes probar esto: en lugar de 'u.save!', Haz 'u.save' y luego' puts u.errors' or 'p u.errors'. ¿Cuáles son los errores? Tengo la sensación de que este es un problema en el que está creando un usuario que no pasa una de las validaciones por exclusividad (ya que está utilizando un 'User.create' genérico sin atributos que se ingresen). – Batkins

Respuesta

5

¿Ha intentado no llamar al f.save!? u.save! debe guardar favoritos y usuarios.

> 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 

creo que lo que se encuentra es que el nuevo favorito f que ha creado es un objeto independiente. Por lo tanto, estará guardando f, mientras que también hay otro favorito no guardado en u.favourites. Por lo tanto, se produce un error no único al guardarlo (que también guarda los favoritos)

No estoy seguro de si este es un error recientemente introducido en Rails 3.1. Puede ser intencional.

En Rails 3.0 find_or_initialize_by no rellenar la matriz

> f = u.favorites.find_or_initialize_by_site_id(123) 

> u.favorites 
==> [] 

Parece que un error - ver https://github.com/rails/rails/pull/3610

+0

Tiene que estar allí porque 'u.save!' Está en un lugar distante en el código de 'f.save!', Y existe la posibilidad de que 'u' no se ensucie y salte el guardado. Quiero saber el motivo por el cual se genera un error. – kenn

Cuestiones relacionadas