Merge pull request #412 from avit/shared-context

Support merging searches using shared context
This commit is contained in:
Jon Atack 2014-08-15 20:26:53 +02:00
commit cd581f81ab
6 changed files with 140 additions and 2 deletions

View File

@ -68,6 +68,22 @@ module Ransack
.type
end
# All dependent JoinAssociation items used in the search query
#
def join_associations
@join_dependency.join_associations
end
def join_sources
raise NotImplementedError,
"ActiveRecord 3.0 does not use join_sources or support joining relations with Arel::Join nodes. Use join_associations."
end
def alias_tracker
raise NotImplementedError,
"ActiveRecord 3.0 does not have an alias tracker"
end
private
def get_parent_and_attribute_name(str, parent = @base)

View File

@ -73,6 +73,30 @@ module Ransack
@engine.connection_pool.columns_hash[table][name].type
end
def join_associations
@join_dependency.join_associations
end
# All dependent Arel::Join nodes used in the search query
#
# This could otherwise be done as `@object.arel.join_sources`, except
# that ActiveRecord's build_joins sets up its own JoinDependency.
# This extracts what we need to access the joins using our existing
# JoinDependency to track table aliases.
#
def join_sources
base = Arel::SelectManager.new(@object.engine, @object.table)
joins = @object.joins_values
joins.each do |assoc|
assoc.join_to(base)
end
base.join_sources
end
def alias_tracker
@join_dependency.alias_tracker
end
private
def get_parent_and_attribute_name(str, parent = @base)

View File

@ -78,7 +78,55 @@ module Ransack
end
end
private
if ::ActiveRecord::VERSION::STRING >= '4.1'
def join_associations
raise NotImplementedError,
"ActiveRecord 4.1 and later does not use join_associations. Use join_sources."
end
# All dependent Arel::Join nodes used in the search query
#
# This could otherwise be done as `@object.arel.join_sources`, except
# that ActiveRecord's build_joins sets up its own JoinDependency.
# This extracts what we need to access the joins using our existing
# JoinDependency to track table aliases.
#
def join_sources
base = Arel::SelectManager.new(@object.engine, @object.table)
joins = @join_dependency.join_constraints(@object.joins_values)
joins.each do |aliased_join|
base.from(aliased_join)
end
base.join_sources
end
else
# All dependent JoinAssociation items used in the search query
#
# Deprecated: this goes away in ActiveRecord 4.1. Use join_sources.
#
def join_associations
@join_dependency.join_associations
end
def join_sources
base = Arel::SelectManager.new(@object.engine, @object.table)
joins = @object.joins_values
joins.each do |assoc|
assoc.join_to(base)
end
base.join_sources
end
end
def alias_tracker
@join_dependency.alias_tracker
end
private
def get_parent_and_attribute_name(str, parent = @base)
attr_name = nil

View File

@ -17,7 +17,7 @@ module Ransack
params = {} unless params.is_a?(Hash)
(params ||= {})
.delete_if { |k, v| [*v].all? { |i| i.blank? && i != false } }
@context = Context.for(object, options)
@context = options[:context] || Context.for(object, options)
@context.auth_object = options[:auth_object]
@base = Nodes::Grouping.new(@context, options[:grouping] || 'and')
@scope_args = {}

View File

@ -6,6 +6,10 @@ module Ransack
describe Context do
subject { Context.new(Person) }
if ::ActiveRecord::VERSION::STRING >= "3.1"
its(:alias_tracker) { should be_a ::ActiveRecord::Associations::AliasTracker }
end
describe '#relation_for' do
it 'returns relation for given object' do
expect(subject.object).to be_an ::ActiveRecord::Relation
@ -30,6 +34,45 @@ module Ransack
end
end
describe "sharing context across searches" do
let(:shared_context) { Context.for(Person) }
before do
Search.new(Person, {:parent_name_eq => 'A'}, context: shared_context)
Search.new(Person, {:children_name_eq => 'B'}, context: shared_context)
end
describe '#join_associations', :if => ::ActiveRecord::VERSION::STRING <= '4.0' do
it 'returns dependent join associations for all searches run against the context' do
parents, children = shared_context.join_associations
expect(children.aliased_table_name).to eq "children_people"
expect(parents.aliased_table_name).to eq "parents_people"
end
it 'can be rejoined to execute a valid query' do
parents, children = shared_context.join_associations
expect { Person.joins(parents).joins(children).to_a }.to_not raise_error
end
end
describe '#join_sources', :if => ::ActiveRecord::VERSION::STRING >= '3.1' do
it 'returns dependent arel join nodes for all searches run against the context' do
parents, children = shared_context.join_sources
expect(children.left.name).to eq "children_people"
expect(parents.left.name).to eq "parents_people"
end
it 'can be rejoined to execute a valid query' do
parents, children = shared_context.join_sources
expect { Person.joins(parents).joins(children).to_a }.to_not raise_error
end
end
end
it 'contextualizes strings to attributes' do
attribute = subject.contextualize 'children_children_parent_name'
expect(attribute).to be_a Arel::Attributes::Attribute

View File

@ -40,6 +40,13 @@ module Ransack
it 'does not raise exception for string :params argument' do
expect { Search.new(Person, '') }.not_to raise_error
end
it 'accepts a context option' do
shared_context = Context.for(Person)
search1 = Search.new(Person, {"name_eq" => "A"}, context: shared_context)
search2 = Search.new(Person, {"name_eq" => "B"}, context: shared_context)
expect(search1.context).to be search2.context
end
end
describe '#build' do