使用Rails 5.2和Postgres 9.6.8
我有一个日期字段,要与map(df, ~mean(is.na(.)))
$line
[1] 0
$col_0001
[1] 0.0109375
$col_0002
[1] 0.0140625
$col_0003
[1] 0.0125
$col_0004
[1] 0.009375
$col_0005
[1] 0.0140625
$col_0006
[1] 0.00625
$col_0007
[1] 0.003125
$col_0008
[1] 0.0078125
$col_0009
[1] 0.0078125
和created_at
分开存储,因为我不在乎时间甚至日期。我真的只想存储月份和年份。
我很好奇是否有办法做到这一点并提供默认值。
在研究这个问题时,我看到建议做的答案:
updated_at
但这不起作用。我尝试将列更改为直t.date :month_and_year, null: false, default: -> { 'NOW()' }
,但我没有设置默认值。
我想我可以将月份和年份分别存储为整数,但是我很好奇是否有人为此提出了一个好的解决方案。
答案 0 :(得分:2)
: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
答案 1 :(得分:1)
我同意mu is too short在他的回答中所说的。但我想在这里补充一点,有一种方法可以通过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 >