Rails中的全局实例变量

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Rails中的全局实例变量相关的知识,希望对你有一定的参考价值。

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

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

enter image description here

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

application.rb中

before_action :count_unpublished

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

_navbar.html.erb

<li>
  <%= link_to recipes_path do %>
     Recipes <span class="badge" style="background-color:#ff7373"><%= @unpublished_count %></span>
  <% end %>
</li>

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

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

答案

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

看看本指南,了解一些想法:Caching with Rails

如果我是你,我不会关心这个,直到我的剖析器告诉我这是一个性能问题。相反,我会努力开发其余的功能。

另一答案
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

另一答案

你陷入了过早优化的陷阱。在进行任何优化之前(大多数情况下会增加代码复杂性),您必须分析代码以找到瓶颈。改善计算总响应时间的一小部分的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更快的代码等。

以上是关于Rails中的全局实例变量的主要内容,如果未能解决你的问题,请参考以下文章

Ruby on rails 辅助方法实例变量

Rails - 从视图中的索引操作访问实例变量属性

以下代码片段是不是容易受到 Rails 5 中 SQL 注入的影响?

Has_many:通过 Rails 4 实例变量不起作用

ruby Rails 5.2读取配置文件并实例化全局对象

Rails,js变量的全局存储