【问题标题】:Using the cache count for acts_as_votable使用acts_as_votable的缓存计数
【发布时间】:2015-10-06 11:07:10
【问题描述】:

我有一个遍历一系列帖子的视图,并且正在计算每个帖子的选票。我知道一般如何进行预加载以及一般如何使用缓存计数器。但是我不知道如何使用acts_as_votable附带的缓存计数器(或者我做错了什么。)

查看:

        <span class="votes">
        <% if current_user.voted_for? link %>
            <%= link_to like_link_path(link), class: "likes active", id: "link-#{link.id}", remote: true, method: :put do %>
            <i class="fa fa-heart"></i> <%= link.cached_votes_total.to_s %>
            <% end %>
        <% else %>
            <%= link_to like_link_path(link), class: "likes", id: "link-#{link.id}", remote: true, method: :put do %>
            <i class="fa fa-heart-o"></i> <%= link.cached_votes_total.to_s %>
            <% end %>
        <% end %>
        </span>

终端:

Link Load (0.4ms)  SELECT  "links".* FROM "links"  ORDER BY "links"."score" DESC LIMIT 10 OFFSET 0
User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (1)
User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["id", 1]]
(0.2ms)  SELECT COUNT(*) FROM "votes" WHERE "votes"."voter_id" = $1 AND "votes"."voter_type" = $2 AND "votes"."votable_id" = $3 AND "votes"."votable_type" = $4 AND "votes"."vote_scope" IS NULL  [["voter_id", 1], ["voter_type", "User"], ["votable_id", 1], ["votable_type", "Link"]]
(0.2ms)  SELECT COUNT(*) FROM "votes" WHERE "votes"."voter_id" = $1 AND "votes"."voter_type" = $2 AND "votes"."votable_id" = $3 AND "votes"."votable_type" = $4 AND "votes"."vote_scope" IS NULL  [["voter_id", 1], ["voter_type", "User"], ["votable_id", 2], ["votable_type", "Link"]]
Rendered home/index.html.erb within layouts/application (24.6ms)
Completed 200 OK in 60ms (Views: 56.9ms | ActiveRecord: 1.6ms)

谢谢!

【问题讨论】:

    标签: ruby-on-rails caching activerecord


    【解决方案1】:

    在我看来并没有什么异常。 voted_for? 方法是 voted_on? 的别名。继续阅读代码,您会发现此方法调用了votes.size &gt; 0,它将触发对数据库的以下查询。 (我猜你的页面上有 2 个链接,对吧?)所以它与缓存的计数字段无关。

    (0.2ms)  SELECT COUNT(*) FROM "votes" WHERE "votes"."voter_id" = $1 AND "votes"."voter_type" = $2 AND "votes"."votable_id" = $3 AND "votes"."votable_type" = $4 AND "votes"."vote_scope" IS NULL  [["voter_id", 1], ["voter_type", "User"], ["votable_id", 1], ["votable_type", "Link"]]
    (0.2ms)  SELECT COUNT(*) FROM "votes" WHERE "votes"."voter_id" = $1 AND "votes"."voter_type" = $2 AND "votes"."votable_id" = $3 AND "votes"."votable_type" = $4 AND "votes"."vote_scope" IS NULL  [["voter_id", 1], ["voter_type", "User"], ["votable_id", 2], ["votable_type", "Link"]]
    

    附:代码在这里:github: voter.rb

    【讨论】:

    • 是的,为了避免每个链接都调用一个查询,我想知道我应该includes 哪个模型。这个问题是关于急切加载的,对吧?这就是我为这个问题创建赏金的原因。
    【解决方案2】:

    这可能不是最好的方法,但它可以帮助预加载用户对单个数据库命中链接的投票:

    1. 在后端的某个地方(例如用户模型),您可以定义类似的方法

      # votable - records, which were voted by user, links in the case
      def preloaded_votes(votable)
        @preloaded_votes ||= Vote.where(voter: self, votable: votable).group(:votable_id).count
      end
      

      此方法将返回类似于{votable_id1 =&gt; count1, votable_id2 =&gt; count2 } 的哈希,其中votable_idN 表示该方法的votable 参数中的元素的ID。

    2. 将当前调用 current_user.voted_for? link 更改为预加载计数 current_user.preloaded_votes.key?(link.id)

    此解决方案增加了一个数据库命中,但允许避免 N+1 查询。此外,附加 SQL 不包含任何表连接。一种可能的改进方法 - 为此类查询添加特殊索引。

    【讨论】:

      猜你喜欢
      • 2014-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-24
      • 1970-01-01
      • 2017-10-26
      相关资源
      最近更新 更多