Merge pull request #412 from avit/shared-context
Support merging searches using shared context
This commit is contained in:
commit
cd581f81ab
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -78,6 +78,54 @@ module Ransack
|
|||
end
|
||||
end
|
||||
|
||||
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)
|
||||
|
|
|
@ -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 = {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue