Разбитые ссылки при выполнении кэширования фрагментов в рельсах
-
11-10-2019 - |
Вопрос
Предположим, есть блог с сообщениями, комментариями и пользователями, которые могут комментировать. У пользователей есть SEO-удобные URL-адреса, такие как http: // localhost: 3000/пользователи/Джон (Это можно легко сделать с помощью permalink_fu).
Модель использует Touch, чтобы упростить кэширование:
class Post
has_many :comments
end
class Comment
belongs_to :post, :touch=>true
end
И код представления будет чем -то вроде этого:
<%= cache @post do %>
<h1><%= @post.title %></h1>
<%= @post.content %>
<%= @post.comments.each do |comment| %>
<%= link_to h(comment.user), comment.user %> said:
<%= comment.content %>
<% end %>
<% end %>
Теперь предположим, что Джон меняет Ник на Джонни - его URL меняется на http: // localhost: 3000/users/johnny. Анкет Из -за того, что вы делаете кэширование фрагментов по сообщениям и комментариям, комментарии Джона будут указывать на неправильный URL Джона, если фрагмент не истек. В этом примере можно вручную прикоснуться или истечь ко всем сообщениям, которые содержат комментарии Джона, но в сложном приложении это потребует очень сложных запросов и кажется очень подверженным ошибкам.
Какая здесь лучшая практика? Должен ли я использовать URL-адреса, такие как URL-адреса, такие как /пользователи /13 вместо /пользователя /Джон? Или, может быть, соблюдать список старых URL -адресов, пока кэш не истек? Ни одно решение для меня не выглядит хорошо.
РЕДАКТИРОВАТЬ: Обратите внимание, что это всего лишь упрощенный пример - определенно очень просто запрашивать сообщения и прикоснуться к ним в этом случае. Но сложное приложение подразумевает много отношений между объектами, что затрудняет отслеживание каждого объекта, который имеет ссылку на пользователя. Я немного исследовал это - Facebook позволяет только один раз установить свое имя пользователя, поэтому этой проблемы не существует.
Решение
Я не вижу, чтобы это было бы сложно истекать кэшированным сообщениями. Установите подметалку:
class UserSweeper < ActionController::Caching::Sweeper
observe User
def after_save(user)
user.comments.collect(&:post).each do |post|
expire_fragment post
end
end
Другие советы
Я бы использовал, например, фильтр до_Саве
class User
has_many :posts
before_save :touch_posts
private
def touch_posts
Post.update_all({:updated_at => Time.now}, {:user_id => self.id}) if self.login_changed?
true
end
end
Один запрос обновить пост каждого пользователя. Не очень сложно.