Câu trả lời:
Trình trợ giúp dấu thời gian chỉ có sẵn trong create_table
khối. Bạn có thể thêm các cột này bằng cách chỉ định các loại cột theo cách thủ công:
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
Mặc dù điều này không có cú pháp ngắn gọn như add_timestamps
phương pháp bạn đã chỉ định ở trên, Rails vẫn sẽ coi các cột này là cột dấu thời gian và cập nhật các giá trị bình thường.
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime
- một phím tắt để tạo di chuyển ở trên.
PG::NotNullViolation: ERROR: column "created_at" contains null value
vì bảng của tôi đã chứa dữ liệu vi phạm ràng buộc không null. Bất kỳ cách nào tốt hơn để làm điều này hơn là loại bỏ các tranh chấp không null lúc đầu và sau đó thêm nó sau?
add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now
. Time.zone.now
chỉ là một ví dụ, bạn nên sử dụng bất kỳ giá trị nào có ý nghĩa cho logic của bạn.
Di chuyển chỉ là hai phương thức lớp (hoặc phương thức cá thể trong 3.1): up
và down
(và đôi khi là change
phương thức cá thể trong 3.1). Bạn muốn các thay đổi của bạn đi vào up
phương thức:
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
Nếu bạn ở 3.1 thì bạn cũng có thể sử dụng change
(cảm ơn Dave):
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
Có lẽ bạn đang bối rối def change
, def change_table
và change_table
.
Xem hướng dẫn di chuyển để biết thêm chi tiết.
change
bây giờ có phương pháp, mặc dù trong trường hợp này, không phải là vấn đề :)
change
đáng được đề cập vì vậy tôi cũng sẽ thêm điều đó.
Mã ban đầu của bạn rất gần bên phải, bạn chỉ cần sử dụng một tên phương thức khác. Nếu bạn đang sử dụng Rails 3.1 trở lên, bạn cần xác định change
phương thức thay vì change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
Nếu bạn đang sử dụng phiên bản cũ hơn, bạn cần xác định up
và down
phương pháp thay vì change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def up
add_timestamps(:users)
end
def down
remove_timestamps(:users)
end
end
Phản hồi của @ user1899434 đã nhận ra rằng một bảng "hiện có" ở đây có thể có nghĩa là một bảng có các bản ghi đã có trong đó, các bản ghi mà bạn có thể không muốn bỏ. Vì vậy, khi bạn thêm dấu thời gian bằng null: false, là mặc định và thường được mong muốn, những bản ghi hiện có đều không hợp lệ.
Nhưng tôi nghĩ rằng câu trả lời có thể được cải thiện, bằng cách kết hợp hai bước thành một lần di chuyển, cũng như sử dụng phương thức add_timestamp có ngữ nghĩa hơn:
def change
add_timestamps :projects, default: Time.zone.now
change_column_default :projects, :created_at, nil
change_column_default :projects, :updated_at, nil
end
Bạn có thể thay thế một số dấu thời gian khác cho DateTime.now
, như nếu bạn muốn các bản ghi có sẵn được tạo / cập nhật vào lúc bình minh thay thế.
Time.zone.now
là những gì nên được sử dụng nếu chúng ta muốn mã của mình tuân theo múi giờ chính xác.
Time.zone.now
là nó sẽ trả về thể hiện Thời gian được tạo khi di chuyển được chạy và chỉ sử dụng thời gian đó làm mặc định. Các đối tượng mới sẽ không nhận được một ví dụ Thời gian mới.
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.timestamps
end
end
end
Các biến đổi có sẵn là
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/groupes/ActiveRecord/ConnectionAd Chap /Table.html
Câu trả lời của Nick Davies là đầy đủ nhất về việc thêm các cột dấu thời gian vào một bảng có dữ liệu hiện có. Nhược điểm duy nhất của nó là nó sẽ tăng ActiveRecord::IrreversibleMigration
lên a db:rollback
.
Nó nên được sửa đổi như vậy để làm việc theo cả hai hướng:
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
không hỗ trợ from
và to
trong phiên bản đó?), Nhưng tôi đã lấy ý tưởng này và tạo ra up/down
các phương thức thay vì một change
phương thức duy nhất và nó hoạt động như một cơ duyên!
def change
add_timestamps :table_name
end
không chắc chắn chính xác khi nào nó được giới thiệu, nhưng trong rails 5.2.1 bạn có thể làm điều này:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
để biết thêm xem " sử dụng phương pháp thay đổi " trong tài liệu di chuyển bản ghi hoạt động.
, null: true
sau:my_table
Tôi đã tạo một hàm đơn giản mà bạn có thể gọi để thêm vào mỗi bảng (giả sử bạn có cơ sở dữ liệu hiện có) các trường created_at và update_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_timestamp (tên_bảng, tùy chọn = {}) công khai
Thêm các dấu thời gian (created_at và update_at) vào tên_bảng. Các tùy chọn bổ sung (như null: false) được chuyển tiếp đến #add_column.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
Các câu trả lời trước đây có vẻ đúng tuy nhiên tôi gặp phải vấn đề nếu bảng của tôi đã có mục.
Tôi sẽ nhận được 'ERROR: cột created_at
chứa null
các giá trị'.
Để khắc phục, tôi đã sử dụng:
def up
add_column :projects, :created_at, :datetime, default: nil, null: false
add_column :projects, :updated_at, :datetime, default: nil, null: false
end
Sau đó, tôi đã sử dụng gem Mig_data để thêm thời gian cho các dự án hiện tại khi di chuyển, chẳng hạn như:
def data
Project.update_all created_at: Time.now
end
Sau đó, tất cả các dự án được tạo sau khi di chuyển này sẽ được cập nhật chính xác. Đảm bảo rằng máy chủ cũng được khởi động lại để Rails ActiveRecord
bắt đầu theo dõi dấu thời gian trên bản ghi.
Rất nhiều câu trả lời ở đây, nhưng tôi cũng sẽ đăng câu hỏi của mình vì không có câu trả lời nào trước đây thực sự hiệu quả với tôi :)
Như một số người đã lưu ý, #add_timestamps
không may thêm null: false
hạn chế, điều này sẽ khiến các hàng cũ không hợp lệ vì chúng không có các giá trị này. Hầu hết các câu trả lời ở đây cho thấy rằng chúng tôi đặt một số giá trị mặc định ( Time.zone.now
), nhưng tôi không muốn làm điều đó bởi vì các dấu thời gian mặc định cho dữ liệu cũ này sẽ không chính xác. Tôi không thấy giá trị trong việc thêm dữ liệu không chính xác vào bảng.
Vì vậy, việc di chuyển của tôi chỉ đơn giản là:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :projects, :created_at, :datetime
add_column :projects, :updated_at, :datetime
end
end
Không null: false
, không có hạn chế khác. Các hàng cũ sẽ tiếp tục hợp lệ với created_at
as NULL
và update_at
as NULL
(cho đến khi một số cập nhật được thực hiện cho hàng). Hàng mới sẽ có created_at
và updated_at
dân cư như mong đợi.
Vấn đề với hầu hết các câu trả lời ở đây là nếu bạn mặc định cho Time.zone.now
tất cả các bản ghi sẽ có thời gian di chuyển được chạy như thời gian mặc định của chúng, đó có thể không phải là điều bạn muốn. Thay vào đó, bạn có thể sử dụng đường ray 5 now()
. Điều này sẽ đặt dấu thời gian cho các bản ghi hiện tại là thời gian di chuyển được chạy và là thời gian bắt đầu của giao dịch cam kết cho các bản ghi mới được chèn.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps :users, default: -> { 'now()' }, null: false
end
end
Sử dụng Time.current
là một phong cách tốt 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
hoặc là
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
Đây là một cách đơn giản để thêm dấu thời gian trong bảng hiện có.
class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
def change
add_timestamps :custom_field_metadata
end
end
Đây có vẻ như là một giải pháp sạch trong Rails 5.0.7 (đã phát hiện ra phương thức 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
Tôi đang trên đường ray 5.0 và không có tùy chọn nào trong số này hoạt động.
Điều duy nhất hoạt động là sử dụng loại là: dấu thời gian và không: datetime
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
Tôi gặp vấn đề tương tự trên Rails 5 khi cố gắng sử dụng
change_table :my_table do |t|
t.timestamps
end
Tôi đã có thể thêm các cột dấu thời gian theo cách thủ công bằng cách sau:
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