2012-03-12 103 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