ActiveRecord::使用默认值存储
Posted
技术标签:
【中文标题】ActiveRecord::使用默认值存储【英文标题】:ActiveRecord::Store with default values 【发布时间】: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'
?
【问题讨论】:
【参考方案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">
【讨论】:
以上是关于ActiveRecord::使用默认值存储的主要内容,如果未能解决你的问题,请参考以下文章
Rails:如何为 Rails activerecord 模型中的属性创建默认值? [复制]
为啥 Rails 5 使用 ApplicationRecord 而不是 ActiveRecord::Base?
为 ActiveMerchant CreditCard 对象实现 find()、save() ActiveRecord 方法
Rails ActiveRecord Timestamp in Epoch 而不是 DateTime 格式
在 Ruby on Rails 3.2.14 / Ruby 2.0.0 / PostgreSQL 9.2.4 中使用 activerecord 从序列中检索 nextval