ActiveRecord:: Сохранить со значениями по умолчанию

Используя новый метод ActiveRecord:: Store для сериализации, документы дают следующую реализацию примера:

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

Можно ли объявлять атрибуты со значениями по умолчанию, что-то вроде:

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

?

Ответ 1

Нет, нет способа указать значения по умолчанию внутри вызова store. Макрос store довольно прост:

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, который вы не хотели.

Если вы хотите указать значения по умолчанию, вы можете использовать hook 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

Ответ 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

Вот что я только что взломал, чтобы решить эту проблему:

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

Ответ 4

попробуйте использовать https://github.com/byroot/activerecord-typedstore gem. Он позволяет установить значение по умолчанию, использовать другой конец проверки.