2011-02-03 36 views
38

Làm thế nào tôi có thể đạt được điều này?Làm thế nào để cập nhật một thuộc tính mà không cần chạm vào thuộc tính updated_at?

cố gắng để tạo ra 2 phương pháp, gọi là

def disable_timestamps 
    ActiveRecord::Base.record_timestamps = false 
end 

def enable_timestamps 
    ActiveRecord::Base.record_timestamps = true 
end 

và phương pháp cập nhật chính nó:

def increment_pagehit 
    update_attribute(:pagehit, pagehit+1) 
end 

lượt timestamps và tắt bằng callbacks như:

before_update :disable_timestamps, :only => :increment_pagehit 
after_update :enable_timestamps, :only => :increment_pagehit 

nhưng nó không phải cập nhật mọi thứ, ngay cả thuộc tính mong muốn (pagehit).

Bạn có lời khuyên nào không? Tôi không muốn phải tạo một bảng khác chỉ để đếm các pagehits.

+0

Hãy thử sử dụng 'update_attributes! (: Pagehit => pagehit + 1)' và xem bạn có gặp phải lỗi nào không. BTW, bạn đã dán 'def disable_timestamps' hai lần do nhầm lẫn ở đây, hay là nó giống nhau trong mã của bạn? – Zabba

+0

Có thể trùng lặp của [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?] (Http://stackoverflow.com/questions/861448/is-there-a-way-to-avoid-automatically-updating-rails-timestamp -fields) –

Trả lời

12

Nếu tất cả các bạn đang muốn làm là tăng số đếm, tôi muốn sử dụng phương pháp increment_counter thay vì:

ModelName.increment_counter :pagehit, id 
+0

Tôi muốn tăng bộ đếm nhưng không thay đổi giá trị updated_at. –

+2

@ kleber-s; increment_counter không thay đổi updated_at. – idlefingers

+0

Công trình này hoạt động và có một cách mới trong Rails 3. Một điều tôi nhận thấy là bộ đếm được tăng lên sau khi xem trang. – lulalala

85

Thay thế cho update_attribute, Trong Rails 3.1+ bạn có thể sử dụng update_column.

update_attribute bỏ qua xác thực, nhưng sẽ chạm vào updated_at và thực hiện cuộc gọi lại.

update_column bỏ qua xác thực, không chạm vào updated_at và không thực hiện cuộc gọi lại.

Do đó, update_column là lựa chọn tuyệt vời nếu bạn không muốn ảnh hưởng đến updated_at và không cần gọi lại.

Xem http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html để biết thêm thông tin.

Cũng lưu ý rằng update_column sẽ cập nhật giá trị của thuộc tính trong mô hình trong bộ nhớ và nó sẽ không bị đánh dấu là bẩn. Ví dụ:

p = Person.new(:name => "Nathan") 
p.save 
p.update_column(:name, "Andrew") 
p.name == "Andrew" # True 
p.name_changed? # False 
+0

Tốt đẹp! Cảm ơn bạn đã thông tin! ;) –

+2

Tương đương Mongoid của 'update_column' là' set', như trong 'person.set (: name, 'Andrew')'. [Mongoid Docs - Nguyên tử Persistence] (http://mongoid.org/en/mongoid/docs/persistence.html#atomic) – colllin

2

Để tránh Monkeypatchingtroubles bạn cũng có thể sử dụng ModelName.update_all cho mục đích này:

def increment_pagehit 
    self.class.update_all({ pagehit: pagehit+1 }, { id: id }) 
end 

này cũng không chạm vào timestamps trên hồ sơ.

2

nó không phải là một ý tưởng tốt để làm điều này:

self.class.update_all({ pagehit: pagehit+1 }, { id: id }) 

nó phải được

self.class.update_all("pagehit = pagehit + 1", { id: id }) 

lý do là nếu hai yêu cầu là song song, trên phiên bản đầu tiên cả hai sẽ cập nhật pagehits với cùng một số, vì nó sử dụng số được lưu trong bộ nhớ Ruby.Tùy chọn thứ hai sử dụng máy chủ sql để tăng số bằng 1, trong trường hợp hai truy vấn này đến cùng một lúc, máy chủ sẽ xử lý chúng sau cái kia và sẽ kết thúc với số lượng trang đúng.

-1

Nếu chính xác là không thực sự quan trọng, và bạn không mong đợi các mã để chạy nhiều lần, bạn có thể thử thay đổi được lưu trong cơ sở dữ liệu giá trị updated_at, như vậy:

u = User.first 
u.name = "Alex 2" # make some changes... 
u.updated_at = u.updated_at + 0.000001.second # alter updated_at 
u.save 

để Rails thực sự sẽ cố gắng lưu cùng một giá trị và không thay thế bằng Time.now.

1

Bạn cũng có decrementincrement (và phiên bản bang) không thay đổi updated_at, không kích hoạt xác thực kích hoạt và rõ ràng là thuận tiện cho bộ đếm/số nguyên.

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