使用CURRENT_TIMESTAMP进行Rails 5.2和Active Record迁移

时间:2018-12-16 17:34:27

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

我有一些需要具有默认值的属性。我已设置迁移,以按如下所示在数据库中设置默认值:

reduce

将默认值直接添加到数据库时,默认值非常有用。但是,如果我在Rails中构建新模型,则一个属性可以按预期工作,而另一个则不能:

const taxItems = [{
    taxCode: '430',
    taxAmount: 2,
    ItemTaxPercentage: 20,
    taxCategory: '2'
  },
  {
    taxCode: '430',
    taxAmount: 4,
    ItemTaxPercentage: 20,
    taxCategory: '2'
  },
  {
    taxCode: '431',
    taxAmount: 5,
    ItemTaxPercentage: 20,
    taxCategory: '2'
  },
  {
    taxCode: '430',
    taxAmount: 6,
    ItemTaxPercentage: 20,
    taxCategory: '2'
  }
]

let op = Object.values(taxItems.reduce((op,cur)=>{
  if(op[cur['taxCode']]){
    op[cur['taxCode']]['taxAmount']+= cur['taxAmount'];
  } else {
    op[cur['taxCode']] = cur
  }
  return op;
},{}))

console.log(op)

这种行为是故意的吗?我还必须在模型中设置默认值吗?为什么class AddDefaultsToModel < ActiveRecord::Migration[5.2] def change change_column :posts, :post_type, :string, default: 'draft' change_column :posts, :date_time, :datetime, default: -> { 'CURRENT_TIMESTAMP' } end end 起作用但post = Post.new post.post_type # draft (as expected) post.date_time # nil (expecting the current date and time) 不起作用?

1 个答案:

答案 0 :(得分:1)

ActiveRecord无法理解您date_time的默认值的含义,因此根本不给date_time一个默认值。然后,当您将行插入数据库(即post.save)时,数据库将使用当前时间戳作为date_time值(当然,假设没有人触摸过date_time)。 Rails不会知道date_time在插入之后有一个值,所以您会得到如下行为:

post = Post.new
post.date_time # `nil` because it hasn't been set at all
# set some other values on `post`...
post.save      # INSERT INTO posts (columns other than date_time...) values (...)
post.date_time # `nil` even thought there is a value in the database
post.reload    # Pull everything out of the database
post.date_time # Now we have a timestamp

您有一些选择:

  1. 保存post.reload后调用post,以获取数据库使用的默认时间戳。

  2. 使用after_initialize挂钩自己设置默认值:

    class Post < ApplicationRecord
      after_initialize if: :new_record? do
        self.date_time = Time.now
      end
    end
    
  3. 使用attributes API手动设置默认值:

    class Post < ApplicationRecord
      attribute :date_time, :datetime, default: ->{ Time.now }
    end
    

    您需要使用lambda(或Proc),以便在正确的时间执行Time.now