Created
July 23, 2013 17:25
-
-
Save pcreux/6064275 to your computer and use it in GitHub Desktop.
Revisions
-
pcreux created this gist
Jul 23, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,80 @@ require 'cancan/model_adapters/active_record_adapter' class CanCan::ModelAdapters::ActiveRecordAdapter # From CanCan def database_records if override_scope @model_class.scoped.merge(override_scope) elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins) mergeable_conditions = @rules.select {|rule| rule.unmergeable? }.blank? if mergeable_conditions # TODO Only use nested queries when necessary # Let's use nested queries BuildNestedRelation.call(@model_class, @rules) else @model_class.where(*(@rules.map(&:conditions))).joins(joins) end else @model_class.scoped(:conditions => conditions, :joins => joins) end end class BuildNestedRelation def self.call(*args) new(*args).call end def initialize(model_class, rules) self.model_class = model_class self.rules = rules end def call model_class.where(query) end private # @return [String] like: # id IN ( SUBQUERY_FOR_RULE_1 ) OR id IN ( SUBQUERY_FOR_RULE_2 ) ... # def query rules.map do |rule| "#{select_id} IN ( #{subquery(rule).to_sql} )" end.join("\nOR\n") end def select_id %|"#{model_class.table_name}"."id"| end # @return [ActiveRecord::Relation] a subquery for the rule passed in def subquery(rule) model_class. select(select_id). joins(joins(rule)). where(conditions(rule)). reorder(nil). # work around ambiguous column error limit(nil). # don't take limit into account offset(nil) # don't take offset into account end # @return conditions statement for the rule passed in def conditions(rule) cancan_adapter(rule).conditions end # @return joins statement for the rule passed in def joins(rule) cancan_adapter(rule).joins end def cancan_adapter(rule) CanCan::ModelAdapters::ActiveRecordAdapter.new(model_class, [rule]) end attr_accessor :model_class, :rules end end