2012-03-12 64 views
10

使用新的ActiveRecord ::商店系列化商店,the docs给出以下示例实现:的ActiveRecord ::使用默认值

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

是否有可能宣布与默认值的属性,以一个类似于:

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

回答

17

不,没有办法在store调用中提供默认值。该store macro很简单:

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

而且所有store_accessor所做的是通过迭代:accessors并为每一个访问和mutator方法。如果你试图用:accessors来使用Hash,那么你最终会在你的store中添加一些你并不认为的东西。

如果你要提供的默认值,那么你可以使用一个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通常在这种情况下,我使用'set if not set'成语,即'self.color || ='blue'; self.homepage || ='rubyonrails.org'。这样可以避免'脏'检查。 – 2012-03-12 05:52:01

+1

@KandadaBoggu:'|| ='唯一的缺点是如果你有布尔属性,使用肮脏使他们都一致。可惜没有像Perl的'// ='那样的“set if not defined”。 – 2012-03-12 06:02:09

+0

是的,这是真的,如果他们使用'|| ='成语,就必须以不同的方式对待布尔。 – 2012-03-12 07:01:46

0

这里就是我刚刚砍死在一起来解决这个问题:

# 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

我想也解决了这一点,最终成为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