Rails has_many关系中缺少触摸选项

Giu*_*ppe 12 activerecord ruby-on-rails

我有2个Rails模型:Book和Category,其中一本书belongs_to是一个类别,一个类别has_many书籍.

类别名称显示在每本书的页面中,并且页面被缓存.

如果我更改了类别名称(例如,从"科幻"到"科幻小说"),那么所有相应的书页都将过时,并且需要"触摸"书籍才能触发HTML重新生成.

能够这样做似乎是有意义的:

class Category << ActiveRecord::Base
  has_many :books, touch: true
end
Run Code Online (Sandbox Code Playgroud)

但是该选项不可用,我想因为该touch机制会实例化每个对象,这可能会导致has_many关系的重大性能损失.

为了避免这种情况,我使用原始SQL如下:

class Category << ActiveRecord::Base
  has_many :books
  after_update -> {
    ActiveRecord::Base.connection.execute "UPDATE books SET updated_at='#{current_time_string}' WHERE category_id=#{id})"
  }
end
Run Code Online (Sandbox Code Playgroud)

这太可怕了.有没有更好的办法?

小智 14

不能使用touchhas_many的关联,它仅适用belongs_to,这是一个事实.

如果我正确理解了您想要的内容,touch:trueBook模型中的答案将无效,因为当您更改Category模型并且视图无法重新生成时,Book对象将不会更新.

所以我认为你的解决方案是最好的.(你也可以用books.update_all(updated_at: Time.now))


roc*_*hus 5

从 Rails 6 开始,ActiveRecord::Relation 上有一个 touch_all 方法可以用一个查询处理这类事情。有上有一个相当不错的博客文章在这里