Missing touch parameter in Rails has_many relation

I have 2 Rails models: a book and a category, where the book belongs_to category, the has_many category.

The category name is displayed on each page of the book, and the pages are cached.

If I changed the name of the category (say, from “Sci Fi” to “Science Fiction”), then all the relevant pages of the book will be outdated, and the books need to be “touched” to cause HTML regeneration.

It would seem to make sense to do:

 class Category << ActiveRecord::Base has_many :books, touch: true end 

But the option is not available , I think, because the touch mechanism will instantiate each object, which can lead to a serious performance hit for has_many .

To avoid this, I use raw SQL as follows:

 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 

This is pretty awful. Is there a better way?

+6
source share
3 answers

You cannot use the touch on has_many association, it only works with belongs_to , which is a fact.

If I understand correctly what you want, answers with touch:true in the book model will not work, because the Book object will not be updated when the category model changes, and the view will not regenerate.

So, I think your solution is better for this. (You can also use books.update_all(updated_at: Time.now) )

+5
source

There is actually a touch option for relationships in ActiveRecord. The only difference from the syntax you expect is that this is an option for sort_to:

 class Book << ActiveRecord::Base belongs_to :categories, touch: true end 

Documentation: http://apidock.com/rails/ActiveRecord/Persistence/touch

0
source

It is available only by the belongs_to method, which should be in your book model. That way you can still use it.

0
source

All Articles