2010-10-01 16 views
9

Aquí es parte de mi código de producción (tuve que forzar saltos de línea):¿Hay find_or_create_by_ que tenga un hash en Rails?

task = Task.find_or_create_by_username_and_timestamp_and_des \ 
cription_and_driver_spec_and_driver_spec_origin(username,tim \ 
estamp,description,driver_spec,driver_spec_origin) 

Sí, estoy tratando de encontrar o crear un objeto único ActiveRecord::Base. Pero en la forma actual es muy feo. En su lugar, me gustaría usar algo como esto:

task = Task.SOME_METHOD :username => username, :timestamp => timestamp ... 

que sé de find_by_something key=>value, pero no es una opción aquí. Necesito que todos los valores sean únicos. ¿Hay algún método que haga lo mismo que find_or_create_by, pero tome un hash como entrada? ¿O algo más con semántica similar?

Respuesta

19

Rails 3.2 primero introducido first_or_create a ActiveRecord. No sólo tiene la funcionalidad requerida, sino que también encaja en el resto de las relaciones ActiveRecord:

Task.where(attributes).first_or_create 

en Rails 3.0 y 3.1:

Task.where(attributes).first || Task.create(attributes) 

En Rails 2.1 hasta 2.3:

Task.first(:conditions => attributes) || Task.create(attributes) 

En las versiones anteriores, siempre puedes escribir un método llamado find_or_create para encapsular esto si lo deseas. Definitivamente hecho yo mismo en el pasado:

class Task 
    def self.find_or_create(attributes) 
    # add one of the implementations above 
    end 
end 
+0

Sí, ciertamente puede añadir a AR :: Base, pero creo que hay algún comportamiento específico del modelo, como si desea elegir columnas únicas específicas para hacer el hallazgo. Pero siempre puedes anularlo también. – wuputah

4

se extiende también al método de @ wuputah tomar en una serie de valores hash, que es muy útil cuando se utiliza dentro de db/seeds.rb

class ActiveRecord::Base 
    def self.find_or_create(attributes) 
    if attributes.is_a?(Array) 
     attributes.each do |attr| 
     self.find_or_create(attr) 
     end 
    else 
     self.first(:conditions => attributes) || self.create(attributes) 
    end 
    end 
end 


# Example 
Country.find_or_create({:name => 'Aland Islands', :iso_code => 'AX'}) 

# take array of hashes 
Country.find_or_create([ 
    {:name => 'Aland Islands', :iso_code => 'AX'}, 
    {:name => 'Albania', :iso_code => 'AL'}, 
    {:name => 'Algeria', :iso_code => 'DZ'} 
]) 
Cuestiones relacionadas