【问题标题】:ActiveRecord::Store with default valuesActiveRecord::使用默认值存储
【发布时间】:2012-03-28 12:28:36
【问题描述】:

使用新的 ActiveRecord::Store 进行序列化,the docs 给出如下示例实现:

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

是否可以使用默认值声明属性,类似于:

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

?

【问题讨论】:

    标签: ruby-on-rails activerecord store


    【解决方案1】:

    不,没有办法在 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 并为每个方法创建访问器和修改器方法。如果您尝试将哈希与 :accessors 一起使用,您最终会在您的 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, @mu 通常在这种情况下我使用set if not set 成语,即self.color ||= 'blue'; self.homepage ||= 'rubyonrails.org'。这避免了dirty 检查..
    • @KandadaBoggu:||= 的唯一缺点是如果你有布尔属性,使用脏值会使它们都保持一致。可惜没有像 Perl 的 //= 这样的“如果未定义则设置”。
    • 是的,没错,如果布尔值使用||= idiom,就必须区别对待。
    【解决方案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
    

    【讨论】:

      【解决方案3】:

      尝试使用https://github.com/byroot/activerecord-typedstore gem。它允许您设置默认值,使用验证结束其他。

      【讨论】:

        【解决方案4】:

        以下代码的优点是默认值不会保存在每个用户记录上,这减少了数据库存储的使用,并且在您想要更改默认值时很容易

        class User < ApplicationRecord
          DEFAULT_SETTINGS = { color: 'blue', homepage: 'rubyonrails.org' }
        
          store :settings, accessors: DEFAULT_SETTINGS.keys
        
          DEFAULT_SETTINGS.each do |key,value|
            define_method(key) {
              settings[key] or value
            }
          end
        end
        

        【讨论】:

          【解决方案5】:

          这是我为了解决这个问题而拼凑起来的:

          # 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"}>
          

          【讨论】:

            猜你喜欢
            • 2010-11-11
            • 2023-03-30
            • 1970-01-01
            • 2010-09-14
            • 2016-05-08
            • 1970-01-01
            • 1970-01-01
            • 2015-07-09
            • 1970-01-01
            相关资源
            最近更新 更多