Rails 5.2 and Active Record migration with CURRENT_TIMESTAMP

霸气de小男生 提交于 2019-12-23 14:56:59

问题


I have some attributes that need to have default values. I've set up my migrations to set the defaults in the database as follows:

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

The defaults work great when adding directly to the database. However, if I build a new model in Rails, one attribute works as expected, the other doesn't:

post = Post.new
post.post_type # draft (as expected)
post.date_time # nil (expecting the current date and time)

Is this behavior deliberate? Do I have to set the default in the model as well? Why does Post#post_type work but not Post#date_time?


回答1:


ActiveRecord doesn't understand what your default value for date_time means so it doesn't give date_time a default value at all. Then, when you insert the row into the database (i.e. post.save), the database will use the current timestamp as the date_time value (presuming of course that no one has touched date_time). Rails won't know that date_time has a value after the insert so you get behavior like this:

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

You have some options:

  1. Call post.reload after saving the post to get the default timestamp that the database used.

  2. Use an after_initialize hook to set the default yourself:

    class Post < ApplicationRecord
      after_initialize if: :new_record? do
        self.date_time = Time.now
      end
    end
    
  3. Use the attributes API to set the default by hand:

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

    You need to use a lambda (or Proc) so that Time.now is executed at the right time.



来源:https://stackoverflow.com/questions/53804787/rails-5-2-and-active-record-migration-with-current-timestamp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!