2009-05-14 37 views
54

Nếu bạn có các cột DB created_atupdated_at Rails sẽ tự động đặt các giá trị đó khi bạn tạo và cập nhật đối tượng mô hình. Có cách nào để lưu mô hình mà không chạm vào các cột đó không?Có cách nào để tránh tự động cập nhật các trường dấu thời gian Rails không?

Tôi đang đưa vào một số dữ liệu cũ và tôi muốn đặt các giá trị đó từ các giá trị tương ứng trong các trường dữ liệu kế thừa (được đặt tên khác). Tôi tìm thấy khi tôi đặt chúng trên mô hình và sau đó lưu mô hình, Rails xuất hiện để ghi đè lên các giá trị đến.

Tất nhiên tôi chỉ có thể đặt tên cột mô hình Rails khác nhau để ngăn chặn điều đó, nhưng sau khi dữ liệu được nhập, tôi muốn Rails làm điều dấu thời gian tự động của nó.

Trả lời

66

Làm điều này trong một di cư hoặc trong một nhiệm vụ cào (hoặc trong the new database seeds nếu bạn đang ở trên đường ray cạnh):

ActiveRecord::Base.record_timestamps = false 
begin 
    run_the_code_that_imports_the_data 
ensure 
    ActiveRecord::Base.record_timestamps = true # don't forget to enable it again! 
end 

Bạn có thể an toàn thiết created_atupdated_at bằng tay, Rails sẽ không phàn nàn .

Lưu ý: Điều này cũng hoạt động trên các mô hình riêng lẻ, ví dụ: User.record_timestamps = false

+3

Bạn thậm chí có thể kéo điều này vào một phương pháp, ví dụ: 'def without_timestamps cũ = ActiveRecord :: Base.record_timestamps ActiveRecord :: Base.record_timestamps = false bắt đầu năng suất đảm bảo ActiveRecord :: Base.record_timestamps = old end end' – nonrectangular

+1

Chúng ta có cần đặt lại thành 'true' ngay cả khi thực thi scrips hoặc mã trong console không? – oldergod

+2

Tôi nghĩ rằng http://stackoverflow.com/a/37193298/1214748 là tốt hơn nhiều. Nó không tắt nó trên toàn cầu cho toàn bộ ứng dụng – maschwenk

28

Bạn có thể đặt sau bên trong chuyển đổi của bạn:

ActiveRecord::Base.record_timestamps = false 

Hoặc altenatively sử dụng update_all:

update_all (cập nhật, điều kiện = nil, options = {})

Cập nhật tất cả hồ sơ với các chi tiết được cung cấp nếu chúng khớp với một tập hợp các điều kiện được cung cấp, giới hạn và đặt hàng ca n cũng được cung cấp . Phương thức này xây dựng một câu lệnh SQL UPDATE đơn và gửi nó thẳng tới cơ sở dữ liệu. Nó không không khởi tạo các mô hình liên quan và nó không kích hoạt các cuộc gọi lại hoạt động.

3

Do đây là một nhập khẩu một lần, bạn có thể làm như sau:

  1. Tạo mô hình sử dụng legacy_created_atlegacy_updated_at lĩnh vực.
  2. Tải dữ liệu cũ. Ánh xạ vào các trường mô hình như mong muốn. Bạn có thể sử dụng #save và thường không lo lắng về việc sử dụng update_all hoặc tương tự và bạn có thể sử dụng gọi lại nếu muốn.
  3. Tạo di chuyển để đổi tên các cột thành created_atupdated_at.
47

sử dụng phương pháp update_column thay vì:

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column

update_column(name, value) 
# Updates a single attribute of an object, without calling save. 

Validation được bỏ qua.

Số lần gọi lại bị bỏ qua.

cột updated_at/updated_on không được cập nhật nếu cột đó có sẵn.

Tăng ActiveRecordError khi được gọi trên đối tượng mới hoặc khi thuộc tính tên được đánh dấu là chỉ đọc.

+0

Lưu ý rằng đối với các cột được tuần tự hóa, bạn sẽ phải tự mình định trước giá trị. – Jared

2

Khi không nhập số lượng lớn, bạn có thể ghi đè lên should_record_timestamps? phương pháp trên mô hình của bạn để thêm các kiểm tra mới vào thời điểm cập nhật cột updated_at.

2

Tôi thích sử dụng một mô-đun mixin để tạm thời tắt thời gian dập trong một khối:

module WithoutTimestamps 
    def without_timestamps 
    old = ActiveRecord::Base.record_timestamps 
    ActiveRecord::Base.record_timestamps = false 
    begin 
     yield 
    ensure 
     ActiveRecord::Base.record_timestamps = old 
    end 
    end 
end 

Sau đó, bạn có thể sử dụng nó bất cứ nơi nào bạn cần nó

class MyModel < ActiveRecord::Base 
    include WithoutTimestamps 

    def save_without_timestamps 
    without_timestamps do 
     save! 
    end 
    end 
end 

Hoặc chỉ cần một one- như sau:

m = MyModel.find(1) 
WithoutTimestamps.without_timestamps do 
    m.save! 
end 
+1

Chỉ là một cảnh báo, đây không phải là chủ đề an toàn. Gần đây đã bị cắn bởi điều này! – Slicedpan

2

Tham khảo các câu trả lời khác, tôi thấy ngạc nhiên khi vô hiệu hóa dấu thời gian cho một đơn mô hình, như trong:

User.record_timestamps = false 

làm việc cho cơ sở dữ liệu phát triển của tôi, nhưng không phải trên cơ sở dữ liệu tiền sản xuất của tôi, chạy trên một máy chủ khác. Tuy nhiên nó hoạt động nếu tôi tắt timestamps cho tất cả các mô hình với

ActiveRecord::Base.record_timestamps = false 

(Tình hình: thay đổi các thuộc tính created_at trong một di chuyển)

21

Rails 5 cung cấp một cách thuận tiện để cập nhật một kỷ lục mà không cần cập nhật nó timestamp updated_at.

Bạn chỉ cần vượt qua touch:false trong khi cập nhật hồ sơ của mình.

>> user = User.first 
>> user.updated_at 
=> Thu, 28 Apr 2016 20:01:57 IST +05:30 
>> user.name = "Jose" 
>> user.save(touch: false) 
=> true 

>> user.updated_at 
=> Thu, 28 Apr 2016 20:01:57 IST +05:30 
+0

Điều này cho đến nay là cách sạch nhất để di chuyển các bản ghi. –

7

Trong Rails 3+, cho một đối tượng, đặt record_timestamps cho đối tượng chứ không phải lớp. Ví dụ:

>> user = User.first 
>> user.updated_at 
=> Tue, 12 Apr 2016 22:47:51 GMT +00:00 
>> user.name = "Jose" 
=> "Jose" 
>> user.record_timestamps = false 
>> user.save 
=> true 
>> user.updated_at 
=> Tue, 12 Apr 2016 22:47:51 GMT +00:00 
>> User.record_timestamps 
=> true 

Bằng cách này, bạn không chạm vào trạng thái toàn cầu đối với các mô hình, và bạn không cần phải nhớ để khôi phục lại các thiết lập trước trong một khối ensure.

Các vấn đề liên quan