回答:
タイムスタンプヘルパーは、create_table
ブロックでのみ使用できます。これらの列を追加するには、列タイプを手動で指定します。
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :users, :created_at, :datetime, null: false
add_column :users, :updated_at, :datetime, null: false
end
end
これはadd_timestamps
上記で指定したメソッドと同じ簡潔な構文ではありませんが、Railsはこれらの列をタイムスタンプ列として扱い、通常どおり値を更新します。
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime
-上記の移行を生成するショートカット。
PG::NotNullViolation: ERROR: column "created_at" contains null value
と、テーブルにnull以外の制約に違反するデータが既に含まれているため、エラーが発生し ます。最初にnullでない制約を削除し、後で追加するよりも、これを行うより良い方法はありますか?
add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now
。Time.zone.now
は単なる例であり、ロジックに適した値を使用する必要があります。
マイグレーションは、2つのクラスメソッド(または3.1のインスタンスメソッド)だけです:(up
および、3.1のインスタンスメソッドのdown
場合もありchange
ます)変更をup
メソッドに入れたい:
class AddTimestampsToUser < ActiveRecord::Migration
def self.up # Or `def up` in 3.1
change_table :users do |t|
t.timestamps
end
end
def self.down # Or `def down` in 3.1
remove_column :users, :created_at
remove_column :users, :updated_at
end
end
3.1を使用している場合は、change
(Daveに感謝)も使用できます。
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
おそらく、あなたは混乱しているdef change
、def change_table
とchange_table
。
詳細については、移行ガイドを参照してください。
change
方法はありますが、この場合は問題ではありません:)
change
が、言及する価値があるので、それも追加します。
元のコードは非常に近く、別のメソッド名を使用する必要があるだけです。Rails 3.1以降を使用している場合は、次のchange
代わりにメソッドを定義する必要がありますchange_table
。
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
古いバージョンを使用している場合は、代わりにup
とdown
メソッドを定義する必要がありますchange_table
。
class AddTimestampsToUser < ActiveRecord::Migration
def up
add_timestamps(:users)
end
def down
remove_timestamps(:users)
end
end
@ user1899434の応答は、ここにある「既存の」テーブルが、すでにレコードが含まれているテーブル、つまり削除したくないレコードである可能性があるという事実に基づいています。したがって、null:false(デフォルトであり、多くの場合望ましい)でタイムスタンプを追加すると、それらの既存のレコードはすべて無効になります。
しかし、2つのステップを1つの移行に結合し、よりセマンティックなadd_timestampsメソッドを使用することで、答えを改善できると思います。
def change
add_timestamps :projects, default: Time.zone.now
change_column_default :projects, :created_at, nil
change_column_default :projects, :updated_at, nil
end
代わりにDateTime.now
、既存のレコードを夜明けに作成/更新する場合など、他のタイムスタンプをに置き換えることができます。
Time.zone.now
コードが正しいタイムゾーンに準拠するようにしたい場合に使用するものです。
Time.zone.now
これは、移行の実行時に作成されたTimeインスタンスを返し、その時間をデフォルトとして使用することです。新しいオブジェクトは新しいTimeインスタンスを取得しません。
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.timestamps
end
end
end
利用可能な変換は
change_table :table do |t|
t.column
t.index
t.timestamps
t.change
t.change_default
t.rename
t.references
t.belongs_to
t.string
t.text
t.integer
t.float
t.decimal
t.datetime
t.timestamp
t.time
t.date
t.binary
t.boolean
t.remove
t.remove_references
t.remove_belongs_to
t.remove_index
t.remove_timestamps
end
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html
Nick Daviesの回答は、既存のデータを含むテーブルにタイムスタンプ列を追加するという点で最も完全です。その唯一の欠点は、それが上昇してしまうことにあるActiveRecord::IrreversibleMigration
上db:rollback
。
両方向で機能するように変更する必要があります。
def change
add_timestamps :campaigns, default: DateTime.now
change_column_default :campaigns, :created_at, from: DateTime.now, to: nil
change_column_default :campaigns, :updated_at, from: DateTime.now, to: nil
end
change_column_default
サポートしていないfrom
とto
?そのバージョンで)、私はこのアイデアを取り、作成したup/down
メソッドを代わりに単一のchange
方法、それが魅力のように働きました!
これが正確にいつ導入されたかはわかりませんが、rails 5.2.1では次のようにできます
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
, null: true
後:my_table
以前の答えは正しいようですが、テーブルにすでにエントリがある場合、問題に直面しました。
「エラー:列created_at
にnull
値が含まれています」と表示されます。
修正するには、次を使用しました:
def up
add_column :projects, :created_at, :datetime, default: nil, null: false
add_column :projects, :updated_at, :datetime, default: nil, null: false
end
次に、gem migration_dataを使用して、次のような移行に関する現在のプロジェクトの時間を追加しました。
def data
Project.update_all created_at: Time.now
end
その後、この移行後に作成されたすべてのプロジェクトが正しく更新されます。Rails ActiveRecord
がレコードのタイムスタンプの追跡を開始できるように、サーバーも再起動されていることを確認してください。
ここにはたくさんの答えがありますが、以前のものは私にとって本当にうまくいかなかったので、私も私が投稿します:)
一部のユーザーが指摘したように、#add_timestamps
残念なことに、null: false
これらの値が入力されていないために古い行が無効になる制限が追加されます。ここでのほとんどの回答は、いくつかのデフォルト値(Time.zone.now
)を設定することを示唆していますが、古いデータのこれらのデフォルトのタイムスタンプは正しくないため、これを行いたくありません。テーブルに誤ったデータを追加しても価値がありません。
だから私の移行は単に:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :projects, :created_at, :datetime
add_column :projects, :updated_at, :datetime
end
end
いいえnull: false
、その他の制限はありません。古い行はcreated_at
as NULL
とupdate_at
asを使用して引き続き有効になりますNULL
(行に対して更新が実行されるまで)。新しい行がありますcreated_at
し、updated_at
期待通りに取り込ま。
ここでのほとんどの回答の問題は、Time.zone.now
すべてのレコードをデフォルトにすると、移行が実行された時刻がデフォルトの時刻になることです。これは、おそらく望ましいことではありません。Rails 5では代わりにを使用できますnow()
。これにより、移行が実行された時間、および新しく挿入されたレコードのコミットトランザクションの開始時間として、既存のレコードのタイムスタンプが設定されます。
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps :users, default: -> { 'now()' }, null: false
end
end
使用Time.current
は良いスタイルですhttps://github.com/rubocop-hq/rails-style-guide#timenow
def change
change_table :users do |t|
t.timestamps default: Time.current
t.change_default :created_at, from: Time.current, to: nil
t.change_default :updated_at, from: Time.current, to: nil
end
end
または
def change
add_timestamps :users, default: Time.current
change_column_default :users, :created_at, from: Time.current, to: nil
change_column_default :users, :updated_at, from: Time.current, to: nil
end
これは、既存のテーブルにタイムスタンプを追加する簡単なものです。
class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
def change
add_timestamps :custom_field_metadata
end
end
これはRails 5.0.7のクリーンなソリューションのようです(change_column_nullメソッドを発見しました):
def change
add_timestamps :candidate_offices, default: nil, null: true
change_column_null(:candidate_offices, :created_at, false, Time.zone.now)
change_column_null(:candidate_offices, :created_at, false, Time.zone.now)
end
私はRails 5で同じ問題に遭遇しました
change_table :my_table do |t|
t.timestamps
end
以下を使用して、タイムスタンプ列を手動で追加できました。
change_table :my_table do |t|
t.datetime :created_at, null: false, default: DateTime.now
t.datetime :updated_at, null: false, default: DateTime.now
end