Rails 5.2 и миграция Active Record с помощью CURRENT_TIMESTAMP - PullRequest
0 голосов
/ 16 декабря 2018

У меня есть некоторые атрибуты, которые должны иметь значения по умолчанию.Я настроил свои миграции для установки значений по умолчанию в базе данных следующим образом:

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

Значения по умолчанию отлично работают при добавлении непосредственно в базу данных.Однако, если я создаю новую модель в Rails, один атрибут работает должным образом, а другой - нет:

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

Является ли это поведение преднамеренным?Должен ли я установить значение по умолчанию в модели?Почему Post#post_type работает, а не Post#date_time?

1 Ответ

0 голосов
/ 16 декабря 2018

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. Call post.reload после сохранения post для получения метки времени по умолчанию, используемой базой данных.

  2. Используйте хук after_initialize, чтобы самостоятельно установить значение по умолчанию:

    class Post < ApplicationRecord
      after_initialize if: :new_record? do
        self.date_time = Time.now
      end
    end
    
  3. Используйте API-атрибут для установки значения по умолчанию вручную:

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

    Вам необходимо использовать лямбду (или Proc), чтобы выполнить Time.nowв нужное время.

...