【问题标题】:How can I set a default value for a date in Rails 5.2 with Postgres?如何使用 Postgres 在 Rails 5.2 中为日期设置默认值?
【发布时间】:2018-09-09 03:49:05
【问题描述】:

使用 Rails 5.2 和 Postgres 9.6.8

我有一个日期字段,我想将它与created_atupdated_at 分开存储,因为我不关心时间,甚至不关心日期。我真的只想存储月份和年份。

我很好奇是否有办法做到这一点并给出一个默认值。

在研究这个问题时,我看到了建议做的答案:

t.date :month_and_year, null: false, default: -> { 'NOW()' }

但这不起作用。我尝试将列更改为直接的datetime,但我从未设置过默认值。

我想我可以将月份和年份分别存储为整数,但我很好奇是否有人为此提出了一个好的解决方案。

【问题讨论】:

  • 查看这篇文章 - bencurtis.com/2014/02/…
  • 该语法似乎已过时。另外,我发现它确实保存了日期,但我总是必须在实例上调用 .reload 才能从数据库中取回值。
  • 另一种无需重新加载即可工作的方法是将当前日期分配给 before_save 回调中的字段。
  • @SampatBadhe 不利的一面是,当您在 @m = Model.new 控制器方法中执行通常的 @m = Model.new 时,您将无法获得默认值。

标签: ruby-on-rails postgresql rails-activerecord


【解决方案1】:

我同意mu is too short 在他的回答中所说的话。但我想在这里补充一点,有一种方法可以通过其新的attribute API 在 ActiveRecord 中进行设置。

例如,如果您在 Post 模型中有列 month_and_year 并且您想为此设置默认值,您可以编写如下:

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 >

【讨论】:

    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-14
      • 2020-01-23
      • 1970-01-01
      • 2010-09-15
      相关资源
      最近更新 更多