2011-01-14 19 views

Respuesta

13

Model.find_or_initialize probablemente haga lo que quiera. Puede encadenarlo con save o update_attributes si tiene sentido.

Más información en el Rails Guides.

+3

ver comentario en la respuesta de Pasta – tybro0103

+1

¿Alguien ha visto esto generar un postre? La guía de rieles indica que el nuevo objeto aún no se almacenará en la base de datos, por lo que no puedo ver cómo se trata de una verdadera actualización de DB. Es decir, no funcionará de manera confiable en un entorno de subprocesos múltiples. – stuckj

+2

Esta solución tiene problemas de concurrencia. Fallará si otro hilo actualiza la tabla entre 'find_or_initialize' y' save'. –

3

También hay Model.find_or_create

+6

Esto no hace un upsert. Hace una selección y luego (opcionalmente) una inserción. Si bien obtienes el mismo efecto en un mundo con un solo subproceso, en un mundo con subprocesos múltiples, necesitarás que se haga un upsert real. – tybro0103

-1

que había escrito un blog el cómo podemos lograr esto. Verifique here.

Tendrá que escribir una extensión de registro activa. Se verá algo como esto.

module ActiveRecordExtension 
    extend ActiveSupport::Concern 

    def self.upsert(attributes) 
    begin 
     create(attributes) 
    rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation => e 
     find_by_primary_key(attributes['primary_key']). 
     update(attributes) 
    end 
    end 
end 

ActiveRecord::Base.send(:include, ActiveRecordExtension) 
+3

No es partidario de usar errores para conducir el flujo lógico esperado, especialmente cuando puede predecir cuándo ocurrirá este error. – kmanzana

+0

buen punto @kmanzana. un poco demasiado hackish para mí. En mi humilde opinión – olleh

0

El mecanismo IMO Upsert requiere una configuración personalizada para cada modelo.

Así que la mejor solución sería implementar una consulta SQL personalizada para un modelo, p. Ej.

insert into <table> (<field_1>, ..., <field_n>) 
    values (<field_1_value>, ..., <field_n_value>) 
on duplicate key update 
    field_x = field_x_value, 
    ... 
    field_z = field_z_value;