Rails中的全局实例变量

时间:2017-12-21 16:44:21

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord

在我的应用中,用户可以通过表单提交食谱,该表格将在网站上发布。在食谱发布之前,他们将通过主持人进行审核。

因此,我的应用程序在导航栏中显示主持人所有当前未发布的食谱的计数,如下所示:

enter image description here

为了实现这一目标,我将执行以下操作:

application.rb中

<Firstname></Firstname>

_navbar.html.erb

before_action :count_unpublished

def count_unpublished
  @unpublished_count = Recipe.where(:published => false).count
end

它有效,但我现在想知道这是一个很好的做法,现在每个动作我的应用程序都会打到配方数据库(这可能不是很优雅)。

有没有更好的解决方案来实现这一目标?

3 个答案:

答案 0 :(得分:3)

为避免命中数据库,您可以引入缓存。它有多种形式:更快的存储(memcached,redis),进程内缓存(全局/类变量)等。并且它们都有相同的问题:您需要知道何时使缓存无效。

请查看本指南以获得一些想法:Caching with Rails

如果我是你,我不会关心这个,直到我的探查者告诉我这是一个性能问题。相反,我会指导我开发剩余的功能。

答案 1 :(得分:3)

cache_key = "#{current_user.id}_#{unpublished_count}"
@unpublished_count = Rails.cache.fetch(cache_key, expires_in: 12.hours) do 
  Recipe.where(:published => false).count
end

更多信息:http://guides.rubyonrails.org/caching_with_rails.html#low-level-caching

答案 2 :(得分:0)

你陷入了过早优化的陷阱。在进行任何优化之前(大多数情况下会增加代码复杂性),您必须分析代码以找到瓶颈。改善计算总响应时间的一小部分的SQL请求是没用的。相反,如果SQL花费了大量时间,那就是一个很大的改进。

为此我可以推荐这两个宝石:

要回答您的问题,最好的方法是:

# app/models/recipe.rb
class Recipe < AR::base
  # A nice scope that you can reuse anywhere
  scope :unpublished, -> { where(published: false) }
end

然后在你的navbar.html.erb中:

<li>
  <%= link_to recipes_path do %>
     Recipes <span class="badge" style="background-color:#ff7373"><%= Recipe.unpublished.count %></span>
  <% end %>
</li>

你在控制器中没有这些丑陋的回调和实例变量。

除非您有很多食谱(类似于100K或更多),否则性能不会成为问题。在这种情况下,您可以添加索引:

CREATE INDEX index_recipes_unpblished ON recipes(published) WHERE published='f' 

请注意,仅当发布为false时,索引才适用。否则会产生反作用。

我认为在你的情况下缓存并不好,因为失效是非常复杂的,并导致可怕的易破坏代码。不要担心打到数据库,我们永远不会编写比PostgreSQL / MySQL等更快的代码。

相关问题