How-to: search across linked tables using acts_as_ferret
I’m in the process of adding search to a Rails application, using acts_as_ferret and ran into this issue. How to search a table using a field from another table, supplied by a foreign key?
Let’s say you created a table for a model named Feature:
create_table "features", :force => true do |t|
t.integer "feature_name_id"
t.integer "chromosome_id"
t.integer "start"
t.integer "end"
t.string "strand"
t.datetime "created_at"
t.datetime "updated_at"
end
This model, Feature, belongs_to two models, FeatureName and Chromosome, each with a field “name”:
create_table "feature_names", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "chromosomes", :force => true do |t|
t.string "name"
t.integer "length"
t.datetime "created_at"
t.datetime "updated_at"
end
You want to search for features using the associated feature_name or chromosome_name.
Here’s the trick. Edit app/models/feature.rb to look something like this (just showing the relevant parts here):
class Feature < ActiveRecord::Base
acts_as_ferret :fields => [:fname,:cname]
belongs_to :feature_name
belongs_to :chromosome
# ferret indexing on foreign keys
def fname
"#{self.feature_name.name}"
end
def cname
"#{self.chromosome.name}"
end
end
That tells acts_as_ferret to index whatever is returned by the methods fname and cname. Which is: the name field from the FeatureName and Chromosome models, respectively.
For testing, I use a small rake task to pre-build indices. Run it with “rake ferret:build”.
namespace :ferret do
# Rebuild index task.
desc "Rebuild a Ferret index."
task :build => :environment do
[Feature,MyOtherModel1,MyOtherModel2].each do |model|
model.rebuild_index
end
end
end
If search isn’t returning results following your changes, don’t forget to restart the server.


