在我的应用中,用户可以通过表单提交食谱,该表格将在网站上发布。在食谱发布之前,他们将通过主持人进行审核。
因此,我的应用程序在导航栏中显示主持人所有当前未发布的食谱的计数,如下所示:
为了实现这一目标,我将执行以下操作:
application.rb中
<Firstname></Firstname>
_navbar.html.erb
before_action :count_unpublished
def count_unpublished
@unpublished_count = Recipe.where(:published => false).count
end
它有效,但我现在想知道这是一个很好的做法,现在每个动作我的应用程序都会打到配方数据库(这可能不是很优雅)。
有没有更好的解决方案来实现这一目标?
答案 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等更快的代码。