Rails (ERB):如果条件不满足,我可以取消片段缓存吗?
Rails (ERB): Can I cancel a fragment cache if a condition fails?
我正在寻找一种简单有效的方法来在条件失败时取消对 ERB 视图中命名片段的缓存写入。
我目前正在这样做:
<% cache("header_#{$I18n.locale}", expires_in: 1.day) do %>
<% begin %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% rescue OpenURI::HTTPError => e %>
Error Loading Remote File: <%= e.message %>
<% end %>
<% end %>
显然其中一些只是为了演示我的问题,而不是展示生产代码的最佳实践。
问题是:上面的代码会缓存错误消息并显示 1 天,而不是在下次加载时重试服务器。
(通常这不会发生在视图中,但在这种情况下,我正在为更大的 rails 应用程序编写一个插件,不能修改控制器,只能修改视图。)
这就是我想要做的:
<% cache("header_#{$I18n.locale}", expires_in: 1.day) do %>
<% begin %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% rescue OpenURI::HTTPError => e %>
--> Some command to cancel the cache action started above
--> Show a backup something to the user (I'll provide)
<% end %>
<% end %>
有人对如何做到这一点有建议吗?
There are two hard problems in computer science: naming things, cache invalidation, and off-by-one errors.
欢迎来到第二个难题。
尝试使用 Rails.cache
而不是 cache
- 我不是 100% 知道有什么区别,或者是否有区别,但是 Rails.cache
为您提供了一些更明显的方法用于缓存操作。
Rails.cache.fetch
采用三个选项:缓存键、选项哈希和块。如果指定的键在缓存中存在且未过期,则return缓存的内容;否则,它将执行块并将其结果存储在缓存中。
<% Rails.cache.fetch "header_#{$I18n.locale}", :expires_in => 1.day do %>
<% begin %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% rescue OpenURI::HTTPError => e %>
<% Rails.cache.delete "header_#{$I18n.locale}" # removes the cache entry %>
<!-- Show your backup here -->
<% end %>
<% end %>
如果这不起作用,则可能取决于缓存操作的完成顺序 - 可能是条目在您的 rescue
块中被删除,但随后在整个过程中重新添加块已完成执行。在那种情况下,试试这个:
<% remove_cache_entry = false %>
<% Rails.cache.fetch "header_#{$I18n.locale}", :expires_in => 1.day do %>
<% begin %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% rescue OpenURI::HTTPError => e %>
<% remove_cache_entry = true %>
<!-- Show your backup here -->
<% end %>
<% end %>
<% Rails.cache.delete "header_#{$I18n.locale}" if remove_cache_entry %>
由于您不想在出现异常时缓存结果,因此您应该将异常处理代码放在 cache
块之外:
<% begin %>
<% cache("header_#{$I18n.locale}", expires_in: 1.day) do %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% end %>
<% rescue OpenURI::HTTPError => e %>
Error Loading Remote File: <%= e.message %>
<% end %>
这样,当缓存块内出现异常时,该块将在完成之前退出,并且不会发生缓存。
我正在寻找一种简单有效的方法来在条件失败时取消对 ERB 视图中命名片段的缓存写入。
我目前正在这样做:
<% cache("header_#{$I18n.locale}", expires_in: 1.day) do %>
<% begin %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% rescue OpenURI::HTTPError => e %>
Error Loading Remote File: <%= e.message %>
<% end %>
<% end %>
显然其中一些只是为了演示我的问题,而不是展示生产代码的最佳实践。
问题是:上面的代码会缓存错误消息并显示 1 天,而不是在下次加载时重试服务器。
(通常这不会发生在视图中,但在这种情况下,我正在为更大的 rails 应用程序编写一个插件,不能修改控制器,只能修改视图。)
这就是我想要做的:
<% cache("header_#{$I18n.locale}", expires_in: 1.day) do %>
<% begin %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% rescue OpenURI::HTTPError => e %>
--> Some command to cancel the cache action started above
--> Show a backup something to the user (I'll provide)
<% end %>
<% end %>
有人对如何做到这一点有建议吗?
There are two hard problems in computer science: naming things, cache invalidation, and off-by-one errors.
欢迎来到第二个难题。
尝试使用 Rails.cache
而不是 cache
- 我不是 100% 知道有什么区别,或者是否有区别,但是 Rails.cache
为您提供了一些更明显的方法用于缓存操作。
Rails.cache.fetch
采用三个选项:缓存键、选项哈希和块。如果指定的键在缓存中存在且未过期,则return缓存的内容;否则,它将执行块并将其结果存储在缓存中。
<% Rails.cache.fetch "header_#{$I18n.locale}", :expires_in => 1.day do %>
<% begin %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% rescue OpenURI::HTTPError => e %>
<% Rails.cache.delete "header_#{$I18n.locale}" # removes the cache entry %>
<!-- Show your backup here -->
<% end %>
<% end %>
如果这不起作用,则可能取决于缓存操作的完成顺序 - 可能是条目在您的 rescue
块中被删除,但随后在整个过程中重新添加块已完成执行。在那种情况下,试试这个:
<% remove_cache_entry = false %>
<% Rails.cache.fetch "header_#{$I18n.locale}", :expires_in => 1.day do %>
<% begin %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% rescue OpenURI::HTTPError => e %>
<% remove_cache_entry = true %>
<!-- Show your backup here -->
<% end %>
<% end %>
<% Rails.cache.delete "header_#{$I18n.locale}" if remove_cache_entry %>
由于您不想在出现异常时缓存结果,因此您应该将异常处理代码放在 cache
块之外:
<% begin %>
<% cache("header_#{$I18n.locale}", expires_in: 1.day) do %>
<%= raw open("https://mywebsite.org/remote/fragment", :read_timeout => 10).read %>
<% end %>
<% rescue OpenURI::HTTPError => e %>
Error Loading Remote File: <%= e.message %>
<% end %>
这样,当缓存块内出现异常时,该块将在完成之前退出,并且不会发生缓存。