2010-10-01 14 views
9

Ecco alcuni dei miei codice di produzione (ho dovuto forzare interruzioni di linea):C'è find_or_create_by_ che accetta un hash in 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ì, sto cercando di trovare o creare un oggetto unico ActiveRecord::Base. Ma nella forma attuale è molto brutto. Invece, mi piacerebbe usare qualcosa di simile:

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

che so di find_by_something key=>value, ma non è un'opzione qui. Ho bisogno che tutti i valori siano unici. C'è un metodo che farà lo stesso come find_or_create_by, ma prendi un hash come input? O qualcos'altro con la semantica simile?

risposta

19

Rails 3.2 ha introdotto per la prima volta first_or_create su ActiveRecord. Non solo ha la funzionalità richiesta, ma si adatta anche nel resto dei rapporti ActiveRecord:

Task.where(attributes).first_or_create 

in Rails 3.0 e 3.1:

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

In Rails 2,1-2,3:

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

Nelle versioni precedenti, si potrebbe sempre scrivere un metodo chiamato find_or_create per incapsulare questo se lo si desidera. Sicuramente fatto io in passato:

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

Sì, si può certamente aggiungere ad AR :: Base, ma trovo che ci sia un comportamento specifico del modello, come se tu volessi scegliere colonne univoche specifiche per fare la ricerca. Ma puoi sempre ignorarlo. – wuputah

4

Ho anche estendere il metodo di @ wuputah a prendere in un array di hash, che è molto utile se usato all'interno 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'} 
]) 
Problemi correlati