在 Rails 中缓存昂贵的非渲染数据列表的最佳实践

发布于 2024-12-10 18:25:10 字数 943 浏览 0 评论 0原文

这是一个一般性问题,但为了理解这一点,让我们讨论一个具体的例子。假设您有一个经常使用包含世界上所有国家/地区列表的表单的应用程序。这些国家/地区存储在数据库的 countries 表中,但该表很少更新,并且仅通过您的 seeds.rb 文件进行更新。

为了能够在每个请求中节省一点时间,我通常按如下方式管理此类事情:

module ApplicationHelper

    def self.get_countries
        countries = Country.order("name asc").all.collect{|country| [country.name, country.name]}
        countries.unshift(["",""])
        countries
    end

    # In production mode (cache_classes = true) this is executed only once, and 
    # will remain cached until you restart your application server
    @@COUNTRIES =  ApplicationHelper.get_countries

    # This would be called from various views
    def countries_for_select(country)
        selected = country.name unless country.nil?
        options_for_select(@@COUNTRIES, selected)
    end
end

这是一个合理的方法吗?

请不要建议将国家/地区列表存储在数据库中。我知道还有其他方法可以管理国家/地区列表。我并不真正关心国家 - 这只是我能想到的最容易理解的例子来说明这个一般性问题。

This is a general question, but to get the point across, let's discuss a specific example. Suppose you have an application that frequently uses forms that include a list of all the countries in the world. The countries are stored in the countries table in your DB, but this table is updated very very rarely, and only through your seeds.rb file.

In order to be able to shave off a little time in each request, I typically manage this sort of thing as follows:

module ApplicationHelper

    def self.get_countries
        countries = Country.order("name asc").all.collect{|country| [country.name, country.name]}
        countries.unshift(["",""])
        countries
    end

    # In production mode (cache_classes = true) this is executed only once, and 
    # will remain cached until you restart your application server
    @@COUNTRIES =  ApplicationHelper.get_countries

    # This would be called from various views
    def countries_for_select(country)
        selected = country.name unless country.nil?
        options_for_select(@@COUNTRIES, selected)
    end
end

Is this a reasonable approach?

Please don't suggest not storing the list of countries in the database. I'm aware there are other ways to manage lists of countries. I'm not really concerned with countries - it's just the easiest to understand example I could think of to illustrate this general question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

绝影如岚 2024-12-17 18:25:10

我不确定“非渲染数据”是什么意思。使用您的方法,表单视图仍然需要遍历所有国家/地区并为每个国家/地区的选择呈现一个选项。

<select id="user_country" name="user[country]">
  <option value="US">United States</option>
  <option value="CA">Canada</option>
  <option value="ET">Etcetera</option>

但是,如果您将选择包装在片段缓存中,则在上次部署后第一次呈现表单时,将呈现选择选项,然后将其缓存到 /tmp/cache 中的单独文件中。然后,在每次加载表单时,rails 将使用该缓存文件,就好像它是部分文件并插入到表单中一样。

<% form_for @user do |form| %>
  <% cache('user_countries_selector') do %>
    <% form.select :country, Country.order("name asc").all.collect{|country [country.name, country.name]}
  <% end %>
  <% etc, etc, etc %>
<% end %>

尽管在实践中,我可能会将 Country.order... 代码移至辅助方法中。使用此方法完全不需要将国家/地区列表缓存到@@COUNTRIES。

如果您需要以其他形式呈现国家/地区选择,则应将不同的键传递给 cache(),因为呈现的选择标记的 ID 和名称将是特定于形式的。

I'm not sure what you mean by "non-rendered data". With your method, the form view still needs to loop through all of the countries and render an option for the select for each one.

<select id="user_country" name="user[country]">
  <option value="US">United States</option>
  <option value="CA">Canada</option>
  <option value="ET">Etcetera</option>

If, however, you wrapped the select in a fragment cache, then the first time the form was rendered after the last deploy, the select options would be rendered and then cached into a separate file in /tmp/cache. Then on every subsequent time the form is loaded, that cached file would be used by rails as if it were a partial and inserted into the form.

<% form_for @user do |form| %>
  <% cache('user_countries_selector') do %>
    <% form.select :country, Country.order("name asc").all.collect{|country [country.name, country.name]}
  <% end %>
  <% etc, etc, etc %>
<% end %>

although, in practice, I would probably move the Country.order... code out to a helper method. Caching the list of countries to @@COUNTRIES is completely unnecessary with this method.

If you need to render a country select in other forms, you should pass a different key to cache() since the id and name of the rendered select tag will be form specific.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文