Использование Rails 5.2 и Postgres 9.6.8
У меня есть поле даты, которое я хочу хранить отдельно от created_at и updated_at, потому что меня не волнует время или даже день. Я действительно просто хочу сохранить месяц и год.
Мне любопытно, есть ли способ сделать это и указать значение по умолчанию.
Исследуя этот вопрос, я увидел ответы, предлагающие:
t.date :month_and_year, null: false, default: -> { 'NOW()' }
но это не работает. Я пытался изменить столбец на прямой datetime, но мне так и не удалось установить значение по умолчанию.
Полагаю, я мог бы хранить месяц и год отдельно как целые числа, но мне любопытно, придумал ли кто-нибудь хорошее решение для этого.
этот синтаксис кажется устаревшим. Кроме того, я обнаружил, что он действительно сохраняет дату, но мне всегда приходится вызывать .reload в экземпляре, чтобы получить значение обратно из БД.
Еще один способ, который работает без перезагрузки, - это назначить текущую дату полю в обратном вызове before_save.
@SampatBadhe Обратной стороной этого является то, что вы не получите значение по умолчанию, когда выполните обычный метод @m = Model.new в методе контроллера def new.





Параметр :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
Я согласен с тем, что му слишком короткий сказано в его ответе. Но я хотел бы добавить здесь, что есть способ настроить его в ActiveRecord с помощью его нового attribute API.
Например, если у вас есть столбец month_and_year внутри модели Post, и вы хотите установить для него значение по умолчанию, вы можете написать это, как показано ниже:
class Post < ApplicationRecord
attribute :month_and_year, :date, default: -> { Date.today }
end
Вышеуказанное установит для вас дату по умолчанию. См. Пример:
Loading development environment (Rails 5.2.1)
2.5.1 :001 > post = Post.new(name: 'Post A', title: 'Post title', content: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.')
=> #<Post id: nil, name: "Post A", title: "Post title", content: "Lorem Ipsum is simply dummy text of the printing a...", created_at: nil, updated_at: nil, month_and_year: "2018-09-09">
2.5.1 :002 > post.save
(0.2ms) BEGIN
Post Create (0.8ms) INSERT INTO "posts" ("name", "title", "content", "created_at", "updated_at", "month_and_year") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["name", "Post A"], ["title", "Post title"], ["content", "Lorem Ipsum is simply dummy text of the printing and typesetting industry."], ["created_at", "2018-09-09 09:52:57.262764"], ["updated_at", "2018-09-09 09:52:57.262764"], ["month_and_year", "2018-09-09"]]
(2.0ms) COMMIT
=> true
2.5.1 :003 > Post.last
Post Load (0.5ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<Post id: 3, name: "Post A", title: "Post title", content: "Lorem Ipsum is simply dummy text of the printing a...", created_at: "2018-09-09 09:52:57", updated_at:"2018-09-09 09:52:57", month_and_year: "2018-09-09">
2.5.1 :004 >
проверьте эту статью - bencurtis.com/2014/02/…