ฉันต้องการเพิ่มการประทับเวลา ( created_at
& updated_at
) ลงในตารางที่มีอยู่ ฉันลองใช้รหัสต่อไปนี้ แต่มันไม่ทำงาน
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_timestamps(:users)
end
end
ฉันต้องการเพิ่มการประทับเวลา ( created_at
& updated_at
) ลงในตารางที่มีอยู่ ฉันลองใช้รหัสต่อไปนี้ แต่มันไม่ทำงาน
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_timestamps(:users)
end
end
คำตอบ:
ตัวช่วยประทับเวลาจะมีเฉพาะใน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
เนื่องจากตารางของฉันมีข้อมูลที่ละเมิดข้อ จำกัด ที่ไม่มีค่าว่างอยู่แล้ว มีวิธีใดที่ดีกว่าในการทำเช่นนี้แทนที่จะลบข้อ จำกัด ที่ไม่ใช่โมฆะในตอนแรกจากนั้นจึงเพิ่มในภายหลัง
add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now
ขึ้นอยู่กับสิ่งที่คุณคิดว่าเหมาะสมที่สุดสำหรับค่าเริ่มต้นที่คุณสามารถทำได้ Time.zone.now
เป็นเพียงตัวอย่างคุณควรใช้ค่าใด ๆ ที่สมเหตุสมผลกับตรรกะของคุณ
การย้ายข้อมูลเป็นเพียงวิธีการเรียนสองวิธี (หรือวิธีการตัวอย่างใน 3.1): up
และdown
(และบางครั้งเป็นchange
วิธีการตัวอย่างใน 3.1) คุณต้องการให้การเปลี่ยนแปลงของคุณเป็นไปตาม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
(ขอบคุณเดฟ):
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 ซึ่งเป็นค่าเริ่มต้นและมักเป็นที่ต้องการบันทึกที่มีอยู่เหล่านั้นจะไม่ถูกต้องทั้งหมด
แต่ฉันคิดว่าคำตอบนั้นสามารถปรับปรุงได้โดยการรวมสองขั้นตอนเข้าด้วยกันในการโยกย้ายครั้งเดียวรวมทั้งใช้เมธอด 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
ซึ่งจะส่งคืนอินสแตนซ์เวลาที่สร้างขึ้นเมื่อมีการเรียกใช้การย้ายข้อมูลและใช้เวลานั้นเป็นค่าเริ่มต้น วัตถุใหม่จะไม่ได้รับอินสแตนซ์เวลาใหม่
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
และใช้งานได้ดี!
def change
add_timestamps :table_name
end
ไม่แน่ใจว่าสิ่งนี้ถูกนำมาใช้อย่างแน่นอน แต่ในทางรถไฟ 5.2.1 คุณสามารถทำได้:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
เพื่อดูเพิ่มเติม " ใช้วิธีการเปลี่ยนแปลง " ในเอกสารการโยกย้ายบันทึกที่ใช้งานอยู่
, null: true
หลังจาก:my_table
ฉันได้สร้างฟังก์ชั่นง่าย ๆ ที่คุณสามารถเรียกเพื่อเพิ่มไปยังแต่ละตาราง (สมมติว่าคุณมีฐานข้อมูลที่มีอยู่) เขตข้อมูลcreated_atและupdated_at :
# add created_at and updated_at to each table found.
def add_datetime
tables = ActiveRecord::Base.connection.tables
tables.each do |t|
ActiveRecord::Base.connection.add_timestamps t
end
end
add_timestamps (table_name, options = {}) พับลิก
เพิ่มคอลัมน์การประทับเวลา (created_at และ updated_at) ลงใน table_name ตัวเลือกเพิ่มเติม (เช่น null: false) จะถูกส่งต่อไปยัง #add_column
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
คำตอบก่อนที่จะดูเหมือนจะถูก แต่ฉันประสบปัญหาหากตารางของฉันมีรายการแล้ว
ฉันจะได้รับ 'ข้อผิดพลาด: คอลัมน์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
เป็นNULL
และupdate_at
เป็นNULL
(จนถึงการปรับปรุงบางส่วนจะดำเนินการเพื่อแถว) แถวใหม่จะมีcreated_at
และupdated_at
เติมตามที่คาดไว้
ปัญหาของคำตอบส่วนใหญ่ที่นี่คือถ้าคุณเริ่มต้นTime.zone.now
ระเบียนทั้งหมดจะมีเวลาที่การโยกย้ายถูกเรียกใช้เป็นเวลาเริ่มต้นซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ ในราง 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 แต่ใช้ activerecord ต่อไปนี้จะเพิ่มคอลัมน์ในโมเดลที่มีอยู่ตัวอย่างเช่นสำหรับฟิลด์จำนวนเต็ม
ActiveRecord::Schema.define do
change_table 'MYTABLE' do |table|
add_column(:mytable, :my_field_name, :integer)
end
end
มันchange
ไม่ใช่change_table
สำหรับ Rails 4.2:
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users)
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
ฉันอยู่บนราง 5.0 และตัวเลือกเหล่านี้ไม่ทำงาน
สิ่งเดียวที่ทำงานได้คือใช้ชนิดเป็น: timestamp และไม่ใช่: datetime
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
ฉันใช้สิ่งต่อไปนี้เป็นการส่วนตัวและปรับปรุงระเบียนก่อนหน้าทั้งหมดด้วยเวลา / วันที่ปัจจุบัน:
add_column :<table>, :created_at, :datetime, default: Time.zone.now, null: false
add_column :<table>, :updated_at, :datetime, default: Time.zone.now, null: false
ฉันพบปัญหาเดียวกันกับ 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