Avoid overwriting association conditions with default scope
When joining ransackable associations in Rails 3, preserve both: * association default_scope * association conditions Combining the stashed JoinAssociation with a separate string join for the "AND" conditions looks like a hack, but there is no cleaner way to extract the default_scope conditions with correct table aliases and merge them back into the association since ActiveRecord rebuilds its own join parts when generating the query.
This commit is contained in:
parent
d5d1cfaacf
commit
9f778e8c6c
|
@ -182,23 +182,19 @@ module Ransack
|
||||||
:build, Polyamorous::Join.new(name, @join_type, klass), parent
|
:build, Polyamorous::Join.new(name, @join_type, klass), parent
|
||||||
)
|
)
|
||||||
found_association = @join_dependency.join_associations.last
|
found_association = @join_dependency.join_associations.last
|
||||||
apply_default_conditions(found_association)
|
|
||||||
|
default_conditions = found_association.active_record.scoped.arel.constraints
|
||||||
|
if default_conditions.any?
|
||||||
|
and_default_conditions = "AND #{default_conditions.reduce(&:and).to_sql}"
|
||||||
|
end
|
||||||
|
|
||||||
# Leverage the stashed association functionality in AR
|
# Leverage the stashed association functionality in AR
|
||||||
@object = @object.joins(found_association)
|
@object = @object.joins(found_association).joins(and_default_conditions)
|
||||||
end
|
end
|
||||||
|
|
||||||
found_association
|
found_association
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_default_conditions(join_association)
|
|
||||||
reflection = join_association.reflection
|
|
||||||
default_scope = join_association.active_record.scoped
|
|
||||||
default_conditions = default_scope.arel.where_clauses
|
|
||||||
if default_conditions.any?
|
|
||||||
reflection.options[:conditions] = default_conditions
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -90,8 +90,8 @@ module Ransack
|
||||||
#
|
#
|
||||||
def join_sources
|
def join_sources
|
||||||
base = Arel::SelectManager.new(@object.engine, @object.table)
|
base = Arel::SelectManager.new(@object.engine, @object.table)
|
||||||
joins = @object.joins_values
|
@object.joins_values.each do |assoc|
|
||||||
joins.each do |assoc|
|
next unless assoc.is_a?(JoinDependency::JoinAssociation)
|
||||||
assoc.join_to(base)
|
assoc.join_to(base)
|
||||||
end
|
end
|
||||||
base.join_sources
|
base.join_sources
|
||||||
|
@ -151,7 +151,7 @@ module Ransack
|
||||||
Constants::STRING_JOIN
|
Constants::STRING_JOIN
|
||||||
when Hash, Symbol, Array
|
when Hash, Symbol, Array
|
||||||
Constants::ASSOCIATION_JOIN
|
Constants::ASSOCIATION_JOIN
|
||||||
when ::ActiveRecord::Associations::JoinDependency::JoinAssociation
|
when JoinDependency::JoinAssociation
|
||||||
Constants::STASHED_JOIN
|
Constants::STASHED_JOIN
|
||||||
when Arel::Nodes::Join
|
when Arel::Nodes::Join
|
||||||
Constants::JOIN_NODE
|
Constants::JOIN_NODE
|
||||||
|
@ -196,23 +196,19 @@ module Ransack
|
||||||
:build, Polyamorous::Join.new(name, @join_type, klass), parent
|
:build, Polyamorous::Join.new(name, @join_type, klass), parent
|
||||||
)
|
)
|
||||||
found_association = @join_dependency.join_associations.last
|
found_association = @join_dependency.join_associations.last
|
||||||
apply_default_conditions(found_association)
|
|
||||||
|
default_conditions = found_association.active_record.scoped.arel.constraints
|
||||||
|
if default_conditions.any?
|
||||||
|
and_default_conditions = "AND #{default_conditions.reduce(&:and).to_sql}"
|
||||||
|
end
|
||||||
|
|
||||||
# Leverage the stashed association functionality in AR
|
# Leverage the stashed association functionality in AR
|
||||||
@object = @object.joins(found_association)
|
@object = @object.joins(found_association).joins(and_default_conditions)
|
||||||
end
|
end
|
||||||
|
|
||||||
found_association
|
found_association
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_default_conditions(join_association)
|
|
||||||
reflection = join_association.reflection
|
|
||||||
default_scope = join_association.active_record.scoped
|
|
||||||
default_conditions = default_scope.arel.where_clauses
|
|
||||||
if default_conditions.any?
|
|
||||||
reflection.options[:conditions] = default_conditions
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -93,9 +93,10 @@ module Ransack
|
||||||
expect(condition.value).to eq 'Ernie'
|
expect(condition.value).to eq 'Ernie'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'preserves default scope conditions for associations' do
|
it 'preserves default scope and conditions for associations' do
|
||||||
search = Search.new(Person, articles_title_eq: 'Test')
|
search = Search.new(Person, published_articles_title_eq: 'Test')
|
||||||
expect(search.result.to_sql).to include 'default_scope'
|
expect(search.result.to_sql).to include 'default_scope'
|
||||||
|
expect(search.result.to_sql).to include 'published'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'discards empty conditions' do
|
it 'discards empty conditions' do
|
||||||
|
|
|
@ -33,6 +33,7 @@ class Person < ActiveRecord::Base
|
||||||
belongs_to :parent, :class_name => 'Person', :foreign_key => :parent_id
|
belongs_to :parent, :class_name => 'Person', :foreign_key => :parent_id
|
||||||
has_many :children, :class_name => 'Person', :foreign_key => :parent_id
|
has_many :children, :class_name => 'Person', :foreign_key => :parent_id
|
||||||
has_many :articles
|
has_many :articles
|
||||||
|
has_many :published_articles, :class_name => 'Article', :conditions => {published: true}
|
||||||
has_many :comments
|
has_many :comments
|
||||||
has_many :authored_article_comments, :through => :articles,
|
has_many :authored_article_comments, :through => :articles,
|
||||||
:source => :comments, :foreign_key => :person_id
|
:source => :comments, :foreign_key => :person_id
|
||||||
|
@ -171,6 +172,7 @@ module Schema
|
||||||
t.string :title
|
t.string :title
|
||||||
t.text :subject_header
|
t.text :subject_header
|
||||||
t.text :body
|
t.text :body
|
||||||
|
t.boolean :published, default: true
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table :comments, :force => true do |t|
|
create_table :comments, :force => true do |t|
|
||||||
|
|
Loading…
Reference in New Issue