OMG!
This shouldn’t have been this difficult, but it has because while there are many cool tutorials are out there, they are mostly outdated, and for some reason, the instruction on Heroku was not accessible.
While I picked acts_as_ferret because Heroku supports it, many seemed to prefer Thinking Sphinx. So, if you are not constrained (like me with Heroku), you should try that out too.
1. Install acts_as_ferret
Full instruction is outlined on github, so you should check it out. You can also find the installation instruction and complete list of methods here, too.
While the instruction asks you to put version name, since Heroku only has version 0.4.3 installed, specifying a version will break it.
So, I put the following line in the config/environment.rb.
config.gem ‘acts_as_ferret’
and did
rake gems:install.
2. Install will_paginate
Follow the instruction here to install will_paginate.
3. Modify config/environment.rb
Inside
Rails::Initializer.run do |config|
loop, add the following lines.
config.gem 'will_paginate', :version => '~> 2.3.11', :source => 'http://gemcutter.org'
config.gem 'acts_as_ferret'
And after the loop, add the following two lines. ActsAsFerret.index_dir is very important, since Heroku doesn’t allow write anywhere except tmp directory.
require 'acts_as_ferret'
ActsAsFerret.index_dir = "#{RAILS_ROOT}/tmp/index"
require 'will_paginate'
4. Modify production.rb
This is one change that wasn’t specified anywhere, and took me a while to figure out. I only found it some obscure forum page. Not too obvious. Assuming your Heroku environment is production, put the following lines in the config/environments/production.rb as well.
require 'acts_as_ferret'
ActsAsFerret.index_dir = "#{RAILS_ROOT}/tmp/index"
5. Modify your model
Specify which fields should be searchable in a model. There are ways to search multiple models, and there are many examples you can find online.
I have the following lines in my Post model to search in :title, :content, and :url fields.
acts_as_ferret :fields => [:title, :content, :url]
6. Search action
It’s up to you where you put your search action. I put it in my Post controller, since that’s all I care about. You could possibly have Search controller and search action. You can change per_page parameter to specify how many results are shown per page.
def search
@query=params[:query]
@total_hits = Post.total_hits(@query)
@posts = Post.paginate_with_ferret(@query, :page => params[:page], :per_page => 5)
end
7. In my layouts/application view, I have the following simple form to pass query parameter.
<% form_tag('/posts/search') do %>
<%= text_field_tag 'query' %>
<%= submit_tag 'Search for articles' %>
<% end %>
8. In search view, I use partial and paginate links to show the results.
Search result for term <%= @query %> resulted in <%= @total_hits %> hits
<%= render :partial => 'post', :collection => @posts %>
<%= will_paginate @posts, :params => {:query => @query} %>
That’s it! Once I did it, it was really easy, but I felt very overwhelmed in the beginning.
I hope this saves someone a lot of time. :)
You should put
ActsAsFerret.index_dir = “#{RAILS_ROOT}/tmp/index”
in initializers/acts_as_ferret.rb
Then you won’t need any of the require statements since all the gems will already be loaded.
This was a very helpful article, thank you. Though I am finding that even with a single dyno app the /tmp directory is so unstable that the indexes often disappear. How’s your mileage with ferret on heroku lately?
krrh, I actually moved on to other search plugin precisely because of /tmp issue with acts_as_ferret on Heroku. I am using acts_as_tsearch, and I couldn’t be happier.
Thanks for sharing this, I have tried it for myself and it worked. Do you have similar posts that I can share also?