Come impostare i valori predefiniti in Rails?

Sto cercando di trovare il modo migliore per impostare i valori predefiniti per gli oggetti in Rails.

Il meglio che posso pensare è di impostare il valore predefinito nel new metodo nel controller.

Qualcuno ha qualche input se questo è accettabile o se c’è un modo migliore per farlo?

“Corretto” è una parola pericolosa in Ruby. Di solito c’è più di un modo per fare qualsiasi cosa. Se sai che vorrete sempre quel valore predefinito per quella colonna su quella tabella, impostandoli in un file di migrazione DB è il modo più semplice:

 class SetDefault < ActiveRecord::Migration def self.up change_column :people, :last_name, :type, :default => "Doe" end def self.down # You can't currently remove default values in Rails raise ActiveRecord::IrreversibleMigration, "Can't remove the default" end end 

Poiché ActiveRecord individua automaticamente le proprietà della tabella e della colonna, verrà impostato lo stesso valore predefinito in qualsiasi modello che lo utilizza in qualsiasi app Rails standard.

Tuttavia, se desideri impostare solo valori predefiniti in casi specifici, ad esempio, è un modello ereditato che condivide una tabella con altri, quindi un altro modo elegante è farlo direttamente nel codice Rails quando viene creato l’object modello:

 class GenericPerson < Person def initialize(attributes=nil) attr_with_defaults = {:last_name => "Doe"}.merge(attributes) super(attr_with_defaults) end end 

Quindi, quando si esegue GenericPerson.new() , verrà sempre Person.new() dell’attributo “Doe” fino a Person.new() meno che non lo si sostituisca con qualcos’altro.

Sulla base della risposta di SFEley, ecco una versione aggiornata / fissa per le versioni più recenti di Rails:

 class SetDefault < ActiveRecord::Migration def change change_column :table_name, :column_name, :type, default: "Your value" end end 

Prima di tutto non è ansible sovraccaricare l’ initialize(*args) in quanto non viene chiamato in tutti i casi.

La tua migliore opzione è inserire i valori predefiniti nella tua migrazione:

 add_column :accounts, :max_users, :integer, :default => 10 

La seconda soluzione migliore è inserire i valori predefiniti nel modello, ma funzionerà solo con attributi inizialmente nulli. Potresti avere problemi come ho fatto con le colonne boolean :

 def after_initialize if new_record? max_users ||= 10 end end 

Hai bisogno di new_record? quindi i valori predefiniti non sovrascrivono i valori caricati dalla base dati.

È necessario ||= per interrompere Rails dai parametri sovrascritti passati nel metodo di inizializzazione.

Puoi anche provare change_column_default nelle tue migrazioni (testato in Rails 3.2.8):

 class SetDefault < ActiveRecord::Migration def up # Set default value change_column_default :people, :last_name, "Smith" end def down # Remove default change_column_default :people, :last_name, nil end end 

change_column_default Documenti API Rails

Se ti riferisci ad oggetti ActiveRecord, hai (più di) due modi per farlo:

1. Utilizzare a: parametro predefinito nel DB

PER ESEMPIO

 class AddSsl < ActiveRecord::Migration def self.up add_column :accounts, :ssl_enabled, :boolean, :default => true end def self.down remove_column :accounts, :ssl_enabled end end 

Maggiori informazioni qui: http://api.rubyonrails.org/classs/ActiveRecord/Migration.html

2. Utilizzare una richiamata

EG before_validation_on_create

Maggiori informazioni qui: http://api.rubyonrails.org/classs/ActiveRecord/Callbacks.html#M002147

In Ruby on Rails v3.2.8, utilizzando il callback after_initialize ActiveRecord, è ansible chiamare un metodo nel modello che assegnerà i valori predefiniti per un nuovo object.

after_initialize callback viene triggersto per ogni object trovato e istanziato da un finder, con after_initialize triggersto dopo l’istanziazione di nuovi oggetti ( vedere Callback di ActiveRecord ).

Quindi, IMO dovrebbe assomigliare a qualcosa:

 class Foo < ActiveRecord::Base after_initialize :assign_defaults_on_new_Foo ... attr_accessible :bar ... private def assign_defaults_on_new_Foo # required to check an attribute for existence to weed out existing records self.bar = default_value unless self.attribute_whose_presence_has_been_validated end end 

Foo.bar = default_value per questa istanza a meno che l'istanza contenga un attribute_whose_presence_has_been_validated precedentemente in fase di salvataggio / aggiornamento. Il default_value verrà quindi utilizzato insieme alla vista per rendere il modulo utilizzando il default_value per l'attributo della bar .

Nel migliore dei casi questo è hacky ...

EDIT: usa "new_record?" per verificare se l'istanziazione da una nuova chiamata

Invece di controllare un valore di attributo, usa il new_record? metodo integrato con rotaie. Quindi, l'esempio sopra dovrebbe apparire come:

 class Foo < ActiveRecord::Base after_initialize :assign_defaults_on_new_Foo, if: 'new_record?' ... attr_accessible :bar ... private def assign_defaults_on_new_Foo self.bar = default_value end end 

Questo è molto più pulito. Ah, la magia di Rails - è più intelligente di me.

Per i campi booleani almeno in Rails 3.2.6, questo funzionerà nella tua migrazione.

 def change add_column :users, :eula_accepted, :boolean, default: false end 

Mettere un 1 o 0 per un valore predefinito non funzionerà qui, poiché è un campo booleano. Deve essere un valore true o false .

Se si stanno solo impostando i valori predefiniti per determinati attributi di un modello di backup del database, prenderei in considerazione l’utilizzo di valori di colonna predefiniti di sql: è ansible chiarire quali tipi di valori predefiniti si stanno utilizzando?

Ci sono un certo numero di approcci per gestirlo, questo plugin sembra un’opzione interessante.

Il suggerimento di sovrascrivere new / initialize è probabilmente incompleto. I binari assegneranno (frequentemente) allocazione per gli oggetti ActiveRecord e le chiamate all’assegnazione non comporteranno le chiamate da inizializzare.

Se stai parlando di oggetti ActiveRecord, dai un’occhiata a overriding after_initialize.

Questi post del blog (non i miei) sono utili:

Valori predefiniti Costruttori predefiniti non chiamati

[Modifica: SFEley sottolinea che Rails analizza il valore predefinito nel database quando istanzia un nuovo object nella memoria: non me ne ero reso conto.]

Avevo bisogno di impostare un valore predefinito proprio come se fosse stato specificato come valore di colonna predefinito nel DB. Quindi si comporta così

 a = Item.new a.published_at # => my default value a = Item.new(:published_at => nil) a.published_at # => nil 

Poiché call_initialize callback viene chiamato dopo aver impostato gli attributi dagli argomenti, non c’era modo di sapere se l’attributo è nullo perché non è mai stato impostato o perché è stato intenzionalmente impostato come nullo. Quindi ho dovuto soffermarmi un po ‘e sono arrivato con questa semplice soluzione.

 class Item < ActiveRecord::Base def self.column_defaults super.merge('published_at' => Time.now) end end 

Funziona alla grande per me. (Rails 3.2.x)

Un potenziale potenziale potenzialmente migliore / più pulito rispetto alle risposte proposte è di sovrascrivere l’accessor, in questo modo:

 def status self['name_of_var'] || 'desired_default_value' end 

Vedi “Sovrascrittura degli accessi predefiniti” nella documentazione di ActiveRecord :: Base e altro da StackOverflow sull’uso di self .

ho risposto a una domanda simile qui .. un modo pulito per farlo è usare Rails attr_accessor_with_default

 class SOF attr_accessor_with_default :is_awesome,true end sof = SOF.new sof.is_awesome => true 

AGGIORNARE

attr_accessor_with_default è stato deprecato in Rails 3.2 .. potresti farlo invece con puro Ruby

 class SOF attr_writer :is_awesome def is_awesome @is_awesome ||= true end end sof = SOF.new sof.is_awesome #=> true 

Se stai parlando di oggetti ActiveRecord, io uso la gem ‘attribute-defaults’.

Documentazione e download: https://github.com/bsm/attribute-defaults

Potresti usare la gem rails_default_value. per esempio:

 class Foo < ActiveRecord::Base # ... default :bar => 'some default value' # ... end 

https://github.com/keithrowell/rails_default_value

Nel caso si abbia a che fare con un modello, è ansible utilizzare l’API Attriutes in Rails 5+ http://api.rubyonrails.org/classs/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute

basta aggiungere una migrazione con un nome di colonna appropriato e quindi nel modello impostarlo con:

 class StoreListing < ActiveRecord::Base attribute :country, :string, default: 'PT' end 

È ansible eseguire l’override del costruttore per il modello ActiveRecord.

Come questo:

 def initialize(*args) super(*args) self.attribute_that_needs_default_value ||= default_value self.attribute_that_needs_another_default_value ||= another_default_value #ad nauseum end