How to update a model's “updated_at” field only for a subset of column updates?

旧时模样 提交于 2019-12-05 16:09:37

Two approaches spring to mind:

  1. Don't use :updated_at for the purpose you are using it for. Instead create a new column, say :post_updated_at, and update it manually on each save that you want to cause the post to move to the top. Rails provides a convenient model mehod for this:

    mypost.touch :post_updated_at
    
  2. When you are updating a column and want :updated_at to remain untouched, use the #update_column method, which directly updates the column in the database with the value you give it. Note that it writes the value to the database verbatim, so you will have to be clever if the column in question is a fancy serialize column or similar.

Here's a replacement for save which lets you blacklist "boring" attributes, ie those which don't trigger a timestamp update. It relies on the Rails 4+ update_columns method to suppress callback methods during a save (be careful about suppressing those).

# Here we configure attribs that won't trigger the timestamp update
IGNORED_ATTRIBS = Set.new %w(reviewed_at view_count)

# A "save" replacement
def fussy_save

  # Calculate any ignored attributes that are pending a save
  all_changed_attribs = Set.new(self.changed_attributes.keys)
  ignored_changed_attribs = IGNORED_ATTRIBS.intersection all_changed_attribs

  # Save the ignored attributes without triggering updated_at
  if ignored_changed_attribs.present?
    self.update_columns self.attributes.slice(*ignored_changed_attribs)
  end

 # perform a normal save only if there are additional attributes present
  if !all_changed_attribs.subset?(IGNORED_ATTRIBS)
    save
  end

end

Implementation note:

The final line above is a regular save. I initially tried doing a save without the check, on the basis that nothing should happen if the ignored attributes have already been saved (since save does nothing, and doesn't update timestamp, if no attribs are saved). But I discovered that changed_attributes is actually Rails' internal, definitive, reference, not just a convenience for developers (not too surprising :). It feels dangerous to start messing with that, so instead I just perform a check and all changed attributes will be saved in the SQL (including the ones just saved by update_columns), but only if there are non-ignored attributes present.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!