重写ActiveRecord关系的count()方法好吗?

时间:2017-10-25 01:17:51

标签: ruby-on-rails activerecord

让我们说我的Rails应用程序中有以下关系:

class Parent < ActiveRecord::Base
  has_many :kids
end

class Kid < ActiveRecord::Base
  belongs_to :parent
end

我希望父母能够看到他们健谈的孩子的列表,并通过该列表分页使用计数。这是一种方法(我知道它有点奇怪,忍受我):

class Parent < ActiveRecord::Base
  has_many :kids do
    def for_chatting
      proxy_association.owner.kids.where(:chatty => true)
    end
  end
end

但是!有些父母有数百万的孩子,即使有良好的数据库索引,p.kids.for_chatting.count也需要很长时间才能运行。我很确定这不能直接修复。但!我可以设置Parent#chatty_kids_count属性并使用数据库触发器正确更新它。然后,我可以:

class Parent < ActiveRecord::Base
  has_many :kids do
    def for_chatting
      parent = proxy_association.owner
      kid_assoc = parent.kids.where(:chatty => true)
      def kid_assoc.count
        parent.chatty_kids_count
      end
    end
  end
end

然后parent.kids.for_chatting.count使用缓存的计数,我的分页速度很快。

但是!在单例关联对象上覆盖count()使得呃 - 哦,我太聪明了我大脑的一部分亮起了很长时间。

我觉得有更清晰的方法来解决这个问题。在那儿?或者这是一个&#34;是的,它是奇怪的,留下评论为什么你这样做,它会很好&#34;那种情况?

1 个答案:

答案 0 :(得分:0)

编辑:

我检查了will_paginate的代码,好像它没有使用AR关系的count方法,但我发现你可以为paginate提供选项total_entries

@kids = @parent.kids.for_chatting.paginate(
  page:          params[:page], 
  total_entries: parent.chatty_kids_count
)
  

这不起作用

     

您可以像这里一样使用包装器进行收集   https://github.com/kaminari/kaminari/pull/818#issuecomment-252788488,   只是覆盖计数方法。

class RelationWrapper < SimpleDelegator
  def initialize(relation, total_count)
    super(relation)
    @total_count = total_count
  end

  def count
    @total_count 
  end
end

# in a controller:
relation = RelationWrapper.new(@parent.kids.for_chatting, parent.chatty_kids_count)