Browse files

Add support for association-filtered faceting

It's a common use case that faceting needs to be scoped to a subset.
Whilst this can be done manually, it's easy to extend the built-in
support for association-filtered searching to faceting as well, e.g:

Currently:

  @facets = Product.facets :with => { :manufacturer_id => @manufacturer.id }

After this commit:

  @facets = @manufacturer.products.facets

Whilst technically this changes current behavior the  difference
between searching and faceting through an association is inconsistent
and I feel it should be considered a bug.
  • Loading branch information...
1 parent 07c2c29 commit c85940e0c45c3297ef6c5bb1c1dc7bca17e9c3d7 @pixeltrix pixeltrix committed Jul 18, 2012
View
1 HISTORY
@@ -1,4 +1,5 @@
Edge:
+* Add support for association-filtered faceting (Andrew White).
* Cast PostgreSQL timestamps to their floored integers (instead of rounding up).
* Don't add array_accum to PostgreSQL v80311 (8.3.?) or newer.
View
19 lib/thinking_sphinx/active_record/has_many_association.rb
@@ -2,16 +2,23 @@ module ThinkingSphinx
module ActiveRecord
module HasManyAssociation
def search(*args)
- options = args.extract_options!
+ @reflection.klass.search(*association_args(args))
+ end
+
+ def facets(*args)
+ @reflection.klass.facets(*association_args(args))
+ end
+
+ private
+
+ def association_args(args)
+ options = args.extract_options!
options[:with] ||= {}
options[:with].merge! default_filter
-
- args << options
- @reflection.klass.search(*args)
+
+ args + [options]
end
- private
-
def attribute_for_foreign_key
foreign_key = @reflection.primary_key_name
stack = [@reflection.options[:through]].compact
View
74 spec/thinking_sphinx/active_record/has_many_association_spec.rb
@@ -41,6 +41,46 @@
end
end
+ describe "facets method" do
+ before :each do
+ Friendship.stub!(:facets => true)
+
+ @person = Person.find(:first)
+ @index = Friendship.sphinx_indexes.first
+ end
+
+ it "should raise an error if the required attribute doesn't exist" do
+ @index.stub!(:attributes => [])
+
+ lambda { @person.friendships.facets "test" }.should raise_error(RuntimeError)
+ end
+
+ it "should add a filter for the attribute into a normal facets call" do
+ Friendship.should_receive(:facets) do |query, options|
+ options[:with][:person_id].should == @person.id
+ end
+
+ @person.friendships.facets "test"
+ end
+
+ it "should add a filter for an aliased attribute into a normal facets call" do
+ @team = CricketTeam.new
+ @team.stub!(:id => 1)
+
+ Person.should_receive(:facets).with do |query, options|
+ options[:with][:team_id].should == @team.id
+ end
+
+ @team.people.facets "test"
+ end
+
+ it "should define indexes for the reflection class" do
+ Friendship.should_receive(:define_indexes)
+
+ @person.friendships.facets 'test'
+ end
+ end
+
describe "search method for has_many :through" do
before :each do
Person.stub!(:search => true)
@@ -75,6 +115,40 @@
end
end
+ describe "facets method for has_many :through" do
+ before :each do
+ Person.stub!(:facets => true)
+
+ @person = Person.find(:first)
+ @index = Person.sphinx_indexes.first
+ end
+
+ it "should raise an error if the required attribute doesn't exist" do
+ @index.stub!(:attributes => [])
+
+ lambda { @person.friends.facets "test" }.should raise_error(RuntimeError)
+ end
+
+ it "should add a filter for the attribute into a normal facets call" do
+ Person.should_receive(:facets).with do |query, options|
+ options[:with][:friendly_ids].should == @person.id
+ end
+
+ @person.friends.facets "test"
+ end
+
+ it "should add a filter for an aliased attribute into a normal facets call" do
+ @team = FootballTeam.new
+ @team.stub!(:id => 1)
+
+ Person.should_receive(:facets).with do |query, options|
+ options[:with][:football_team_id].should == @team.id
+ end
+
+ @team.people.facets "test"
+ end
+ end
+
describe 'filtering sphinx scopes' do
before :each do
Friendship.stub!(:search => Friendship)

0 comments on commit c85940e

Please sign in to comment.