2012-03-12 20 views
10

Usando el nuevo ActiveRecord :: tienda para la serialización, the docs dar el ejemplo siguiente aplicación:tienda ActiveRecord :: con valores por defecto

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

¿Es posible declarar atributos con valores por defecto, algo parecido a:

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

?

Respuesta

17

No, no hay manera de proporcionar los valores predeterminados dentro de la llamada store. El store macro es bastante simple:

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

Y todo store_accessor hace es iterar a través de la :accessors y crear métodos de acceso o modificadores para cada uno. Si intenta utilizar un Hash con :accessors, terminará agregando algunas cosas a su store que no pretendía.

Si desea proporcionar valores por defecto entonces se podría utilizar un after_initialize gancho:

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 usualmente en este escenario utilizo la expresión 'set if not set', es decir' self.color || = 'blue'; self.homepage || = 'rubyonrails.org''. Esto evita las verificaciones 'sucias' ... –

+1

@KandadaBoggu: El único inconveniente de '|| =' es que si tiene atributos booleanos, usar la suciedad hace que sean consistentes. Es una pena que no haya un "conjunto si no definido" como Perl's '// ='. –

+0

Sí, es cierto, uno tiene que tratar a los booleanos de manera diferente si usan '|| =' modismo idiomático. –

0

Aquí es lo que acabo hackeado juntos para resolver este 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

que quería resolver esto también y terminó contribuyendo 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 
Cuestiones relacionadas