开发者

Forcing ActiveRecord to count distinct (with Kaminari)

开发者 https://www.devze.com 2023-03-20 05:10 出处:网络
I\'m using Kaminari to paginate some result from a query in which I\'m selecting distinct records. Consider the following controller code:

I'm using Kaminari to paginate some result from a query in which I'm selecting distinct records. Consider the following controller code:

@things = Thing.joins... # create a complex query that produces duplicate results

# I want to select distinct results: this produces the correct results
@things = @things.select("DISTINCT things.*")

# when Kaminari calls count, it will run "SELECT COUNT(*)", instead of 
# "SELECT COUNT(DISTINCT things.*)" we will get the wrong count and extra 开发者_StackOverflow中文版pages
@things = @things.page(params[:page]).per(10)

The best solution that I can think of is to pass :distinct => true to count, like in this pull request, which was rejected by Kaminari's developer. This SO question discusses the underlying problem. This line of code is the offending call to count.

Are there any workarounds that will provide Kaminari with the correct count that don't involve patching Kaminari? Thanks.

UPDATE:

  • Using a scope called "count" is a great suggestion but doesn't work when called on an ActiveRecord::Relation. It works when called on my model class, but that doesn't help.


please refer to the following url.

https://github.com/amatsuda/kaminari/pull/77

https://github.com/tbeauvais/kaminari/commit/23695cbdc4ff1b9fa58c18d4a3c2f18e21451b8b but ,they faild on Rails 3.1.0.

For Rails 3.1.0, create Rails.root/initializers/kaminari_for_distinct.rb. And use the following code.

module Kaminari
  module ActiveRecordRelationMethods
    extend ActiveSupport::Concern
    module InstanceMethods
      def total_count #:nodoc:
        if distinct_column_name.nil?
          c = except(:offset, :limit).count
        else  
          c = except(:offset, :limit).count(distinct_column_name, :distinct => true)
        end
        # .group returns an OrderdHash that responds to #count
        c.respond_to?(:count) ? c.count : c
      end

      # Get the column name used in distinct query.
      # This could have been set on the Model class, or the ActiveRecord::Relation 
      def distinct_column_name
        @distinct_column || distinct_column
      end
    end
  end
end

module Kaminari
  module ConfigurationMethods
    extend ActiveSupport::Concern
    module ClassMethods

      # Set the name of the column to use during .count()
      # Setting this will cause call to count to use: count(:id, :distinct => true) for all the Models paged queries. 
      # Example:
      #   class User < ActiveRecord::Base
      #     use_distinct :id
      #   end
      def use_distinct(column)
        @distinct_column = column
      end

      # Returns the distinct column name set on the Model, or nil if not using distinct
      def distinct_column
        @distinct_column
      end
    end
  end
end


module Kaminari
  module PageScopeMethods
    extend ActiveSupport::Concern
    module InstanceMethods

      # Set the name of the column to use during .count()
      # Setting this will cause call to count to use: count(:id, :distinct => true)
      # Example: User.page(3).per(5).use_distinct(:id)
      def use_distinct(column)
        @distinct_column = column
        self
      end
    end
  end
end


I would suggest a scope on the Model

This might confuse things though so you want to be careful

scope :count, select("DISTINCT things.*")

For more information look here

0

精彩评论

暂无评论...
验证码 换一张
取 消