Параметр :default
заканчивается как часть определения таблицы в базе данных. Итак, это:
t.date :month_and_year, null: false, default: -> { 'NOW()' }
становится SQL следующим образом:
create table ... (
...
month_and_year date not null default now(),
...
)
ActiveRecord будет использовать значения по умолчанию из таблицы , если , то сможет их понять. Если у вас есть простое значение по умолчанию, подобное этому:
some_column integer default 6
тогда ActiveRecord будет использовать это значение по умолчанию, потому что оно знает, что такое 6
и как с ним работать.
В вашем случае значением по умолчанию в базе данных является вызов функции базы данных now()
, но AR не знает, что означает now()
, поэтому не устанавливает значение по умолчанию во вновь созданной модели. Когда эта модель будет сохранена в базе данных, month_and_year
не будет, поэтому база данных будет использовать значение по умолчанию для столбца month_and_year
в новой строке; Конечно, ActiveRecord ничего об этом не узнает, поэтому вам нужно вызвать reload
, чтобы получить значение month_and_year
из базы данных.
Как вы можете решить это? Вы можете использовать after_initialize
крючок следующим образом:
after_initialize if: :new_record? do
if(month_and_year.nil?)
self.month_and_year = Date.today
end
end
Я делаю такого рода вещи достаточно, что у меня возникло простое беспокойство:
module RecordDefaults
extend ActiveSupport::Concern
module ClassMethods
#
# Examples:
#
# use_defaults number: 6,
# %i[time1 time2] => Time.method(:now),
# array: [6, 11, 23, 42]
#
def use_defaults(defs)
after_initialize if: :new_record? do
defs.each do |attrs, value|
if(value.respond_to?(:call))
value = instance_exec(&value)
else
value = value.dup
end
attrs_without_values = ->(a) { send(a).nil? }
use_the_default = ->(a) { send("#{a}=", value) }
Array(attrs).select(&attrs_without_values).each(&use_the_default)
end
end
end
end
end
и затем:
class SomeModel < ApplicationRecord
include RecordDefaults
use_defaults month_and_year: Date.method(:today)
end