Как установить значение по умолчанию для столбца datetime, чтобы записать время создания в миграции?

Рассмотрим создание таблицы script ниже:

create_table :foo do |t|
  t.datetime :starts_at, :null => false
end

Можно ли установить значение по умолчанию в качестве текущего времени?

Я пытаюсь найти DB независимый эквивалент в rails для определений столбцов SQL, приведенных ниже:

Синтаксис Oracle

start_at DATE DEFAULT SYSDATE() 

Синтаксис MySQL

start_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

ИЛИ

start_at DATETIME DEFAULT NOW()

Ответ 1

Теперь это поддерживается в Rails 5.

Вот пример миграции:

class CreatePosts < ActiveRecord::Migration[5.0]
  def change
    create_table :posts do |t|
      t.datetime :modified_at, default: -> { 'CURRENT_TIMESTAMP' }
      t.timestamps
    end
  end 
end

См. обсуждение https://github.com/rails/rails/issues/27077 и ответьте там пратамеш-сотатками

Ответ 2

Вы можете добавить функцию в такую ​​модель:

  before_create :set_foo_to_now
  def set_foo_to_now
    self.foo = Time.now
  end

Чтобы модель установила текущее время в модели.

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

execute 'alter table foo alter column starts_at set default now()'

Настройка примерно так:

create_table :foo do |t|
  t.datetime :starts_at, :null => false, :default => Time.now
end

вызывает выполнение функции Time.now во время миграции, поэтому таблица в базе данных создается следующим образом:

create table foo ( starts_at timestamp not null default '2009-01-01 00:00:00');

но я думаю, что это не то, что вы хотите.

Ответ 3

Если у вас есть столбец datetime с именем created_at или created_on, ActiveRecord "волшебным образом" настроит его на дату создания. Вам не нужно ничего делать, кроме как иметь этот столбец.

Вы также можете иметь updated_at или updated_on, и он будет обновляться при обновлении записи.

Ответ 4

Я искал похожие решения, но я закончил использование https://github.com/FooBarWidget/default_value_for.

Плагин default_value_for позволяет объявлять значения по умолчанию для моделей ActiveRecord декларативным образом. Например:

class User < ActiveRecord::Base
  default_value_for :name, "(no name)"
  default_value_for :last_seen do
    Time.now
  end
end

u = User.new
u.name       # => "(no name)"
u.last_seen  # => Mon Sep 22 17:28:38 +0200 2008

Ответ 5

Я обычно делаю:

def change
  execute("
    ALTER TABLE your_table
    ALTER COLUMN your_column
    SET DEFAULT CURRENT_TIMESTAMP
  ")
end

Итак, ваш schema.rb будет иметь что-то вроде:

create_table "your_table", force: :cascade do |t|
  t.datetime "your_column", default: "now()"
end

Ответ 6

Если вам нужно изменить существующий столбец DateTime в Rails 5 (вместо создания новой таблицы, как указано в других ответах), чтобы он мог использовать возможность по умолчанию для даты, вы можете создать миграция:

class MakeStartsAtDefaultDateForFoo < ActiveRecord::Migration[5.0]
  def change
    change_column :foos, :starts_at, :datetime, default: -> { 'CURRENT_TIMESTAMP' }
  end
end

Ответ 7

На Rails 5.1

class CreateClients < ActiveRecord::Migration[5.1]
  def change
    create_table :cars do |t|
      *******************************
      t.datetime :starts_at, :null => false, default: -> {'CURRENT_TIMESTAMP'}
      *******************************
      t.timestamps
    end
  end
end

Ответ 8

В ответе @szymon-lipiński (Szymon Lipiński) метод выполнения не работал у меня. Это метало ошибку синтаксиса MySQL.

Синтаксис MySQL, который работал у меня, это.

execute "ALTER TABLE mytable CHANGE `column_name` `column_name` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"

Итак, чтобы установить значение по умолчанию для столбца datetime в миграции script, можно сделать следующее:

def up
  create_table :foo do |t|
    t.datetime :starts_at, :null => false
  end

  execute "ALTER TABLE `foo` CHANGE `starts_at` `starts_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"
end