有一个典型的博客应用程序。每个用户都有_many 个帖子。每个帖子都有_many标签。我按 updated_at 对每个帖子进行排序,因此最近更新的帖子将显示在顶部。因此,例如,如果我更新帖子的内容,该帖子将出现在顶部。但是,当我只添加一个标签时也会发生这种情况,因为一个标签连接到其相应的帖子。
我只希望内容更新更改 updated_at 字段。我不希望 updated_at 更改帖子,因为我添加了标签。有没有办法做到这一点?或任何其他方式来实现这样的事情?谢谢!
有一个典型的博客应用程序。每个用户都有_many 个帖子。每个帖子都有_many标签。我按 updated_at 对每个帖子进行排序,因此最近更新的帖子将显示在顶部。因此,例如,如果我更新帖子的内容,该帖子将出现在顶部。但是,当我只添加一个标签时也会发生这种情况,因为一个标签连接到其相应的帖子。
我只希望内容更新更改 updated_at 字段。我不希望 updated_at 更改帖子,因为我添加了标签。有没有办法做到这一点?或任何其他方式来实现这样的事情?谢谢!
我想到了两种方法:
不要:updated_at
用于您使用它的目的。而是创建一个新列,例如:post_updated_at
,并在每次保存时手动更新它,以使帖子移动到顶部。Rails 为此提供了一种方便的模型方法:
mypost.touch :post_updated_at
当您更新列并希望:updated_at
保持不变时,请使用该#update_column
方法,该方法直接使用您给它的值更新数据库中的列。请注意,它将值逐字写入数据库,因此如果有问题的列是花哨的serialize
列或类似的列,您必须很聪明。
这是一个替代品,save
可让您将“无聊”属性列入黑名单,即那些不触发时间戳更新的属性。它依赖 Rails 4+update_columns
方法在保存期间抑制回调方法(小心抑制这些方法)。
# 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
实施说明:
上面的最后一行是常规保存。我最初尝试在没有检查的情况下进行保存,基于如果已保存忽略的属性则不会发生任何事情(因为save
什么都不做,并且如果没有保存属性,则不会更新时间戳)。但我发现这changed_attributes
实际上是 Rails 内部的、明确的、参考,而不仅仅是对开发人员的方便(不太令人惊讶:)。开始弄乱它感觉很危险,所以我只是执行检查,所有更改的属性都将保存在 SQL 中(包括刚刚由 update_columns 保存的属性),但前提是存在未忽略的属性。