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:
Andrew Vit 2015-07-09 13:41:41 -07:00
parent d5d1cfaacf
commit 9f778e8c6c
4 changed files with 22 additions and 27 deletions

View File

@ -182,23 +182,19 @@ module Ransack
:build, Polyamorous::Join.new(name, @join_type, klass), parent
)
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
@object = @object.joins(found_association)
@object = @object.joins(found_association).joins(and_default_conditions)
end
found_association
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

View File

@ -90,8 +90,8 @@ module Ransack
#
def join_sources
base = Arel::SelectManager.new(@object.engine, @object.table)
joins = @object.joins_values
joins.each do |assoc|
@object.joins_values.each do |assoc|
next unless assoc.is_a?(JoinDependency::JoinAssociation)
assoc.join_to(base)
end
base.join_sources
@ -151,7 +151,7 @@ module Ransack
Constants::STRING_JOIN
when Hash, Symbol, Array
Constants::ASSOCIATION_JOIN
when ::ActiveRecord::Associations::JoinDependency::JoinAssociation
when JoinDependency::JoinAssociation
Constants::STASHED_JOIN
when Arel::Nodes::Join
Constants::JOIN_NODE
@ -196,23 +196,19 @@ module Ransack
:build, Polyamorous::Join.new(name, @join_type, klass), parent
)
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
@object = @object.joins(found_association)
@object = @object.joins(found_association).joins(and_default_conditions)
end
found_association
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

View File

@ -93,9 +93,10 @@ module Ransack
expect(condition.value).to eq 'Ernie'
end
it 'preserves default scope conditions for associations' do
search = Search.new(Person, articles_title_eq: 'Test')
it 'preserves default scope and conditions for associations' do
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 'published'
end
it 'discards empty conditions' do

View File

@ -33,6 +33,7 @@ class Person < ActiveRecord::Base
belongs_to :parent, :class_name => 'Person', :foreign_key => :parent_id
has_many :children, :class_name => 'Person', :foreign_key => :parent_id
has_many :articles
has_many :published_articles, :class_name => 'Article', :conditions => {published: true}
has_many :comments
has_many :authored_article_comments, :through => :articles,
:source => :comments, :foreign_key => :person_id
@ -171,6 +172,7 @@ module Schema
t.string :title
t.text :subject_header
t.text :body
t.boolean :published, default: true
end
create_table :comments, :force => true do |t|