2012-03-12 18 views
10

Utilizzando il nuovo ActiveRecord :: Store per la serializzazione, the docs dare il seguente esempio di implementazione:ActiveRecord :: Store con i valori di default

class User < ActiveRecord::Base 
    store :settings, accessors: [ :color, :homepage ] 
end 

E 'possibile dichiarare attributi con valori di default, qualcosa di simile a:

store :settings, accessors: { color: 'blue', homepage: 'rubyonrails.org' } 

?

risposta

17

No, non è possibile fornire i valori predefiniti all'interno della chiamata store. Il store macro è abbastanza semplice:

def store(store_attribute, options = {}) 
    serialize store_attribute, Hash 
    store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors 
end 

E tutto store_accessor non fa altro che scorrere l':accessors e creare metodi di accesso e mutatori per ciascuno di essi. Se tenti di utilizzare un hash con :accessors, finirai per aggiungere alcune cose al tuo store che non volevi.

Se si desidera fornire valori di default allora si potrebbe utilizzare un gancio after_initialize:

class User < ActiveRecord::Base 
    store :settings, accessors: [ :color, :homepage ] 
    after_initialize :initialize_defaults, :if => :new_record? 
private 
    def initialize_defaults 
    self.color = 'blue'   unless(color_changed?) 
    self.homepage = 'rubyonrails.org' unless(homepage_changed?) 
    end 
end 
+1

+1, @mu di solito in questo scenario io uso l'idioma 'set if not set', cioè' self.color || = 'blue'; self.homepage || = 'rubyonrails.org''. Questo evita i controlli 'dirty'. –

+1

@KandadaBoggu: l'unico svantaggio di' || = 'è che se si hanno attributi booleani, l'uso della sporcizia li rende tutti coerenti. Peccato che non ci sia un "set se non definito" come Perl's '// ='. –

+0

Sì, è vero, si devono trattare i booleani in modo diverso se usano l'idioma '|| ='. –

0

Ecco quello che ho appena messo insieme per risolvere questo problema:

# migration 
    def change 
    add_column :my_objects, :settings, :text 
    end 

# app/models/concerns/settings_accessors_with_defaults.rb 
module SettingsAccessorsWithDefaults 
    extend ActiveSupport::Concern 

    included do 
    serialize :settings, Hash 
    cattr_reader :default_settings 
    end 

    def settings 
    self.class.default_settings.merge(self[:settings]) 
    end 

    def restore_setting_to_default(key) 
    self[:settings].delete key 
    end 

    module ClassMethods 
    def load_default_settings(accessors_and_values) 
     self.class_variable_set '@@default_settings', accessors_and_values 

     self.default_settings.keys.each do |key| 
     define_method("#{key}=") do |value| 
      self[:settings][key.to_sym] = value 
     end 

     define_method(key) do 
      self.settings[key.to_sym] 
     end 
     end 
    end 
    end 
end 

# app/models/my_object.rb 
    include SettingsAccessorsWithDefaults 
    load_default_settings(
    attribute_1: 'default_value', 
    attribute_2: 'default_value_2' 
) 
    validates :attribute_1, presence: true 


irb(main):004:0> MyObject.default_settings 
=> {:attribute_1=>'default_value', :attribute_2=>'default_value_2'} 
irb(main):005:0> m = MyObject.last 
=> #<MyObject ..., settings: {}> 
irb(main):005:0> m.settings 
=> {:attribute_1=>'default_value', :attribute_2=>'default_value_2'} 
irb(main):007:0> m.attribute_1 = 'foo' 
=> "foo" 
irb(main):008:0> m.settings 
=> {:attribute_1=>"foo", :attribute_2=>'default_value_2'} 
irb(main):009:0> m 
=> #<MyObject ..., settings: {:attribute_1=>"foo"}> 
2

ho voluto per risolvere anche questo e ha finito per contribuire a Storext:

class Book < ActiveRecord::Base 
    include Storext.model 

    # You can define attributes on the :data hstore column like this: 
    store_attributes :data do 
    author String 
    title String, default: "Great Voyage" 
    available Boolean, default: true 
    copies Integer, default: 0 
    end 
end 
Problemi correlati