Ransack: Would an ActsAsTaggableOn extension for Ransack be possible?

Created on 31 Aug 2012  路  15Comments  路  Source: activerecord-hackery/ransack

Hi,

we just started using Ransack and I have to say, I really, really love it's API!

We are also using ActsAsTaggableOn (https://github.com/mbleigh/acts-as-taggable-on) and I was wondering what it would take to write something like a Ransack "extension" or so to integrate with ActsAsTaggableOn?

# model
class User < ActiveRecord::Base
  acts_as_taggable
  acts_as_taggable_on :skills, :interests
end

# view
f.text_field :tagged_with_skills
f.text_field :tagged_with_skills_any
...

# would be translated into:
User.tagged_with(params[:q][:tagged_with_skills], :on => :skills)
User.tagged_with(params[:q][:tagged_with_skills], :on => :skills, :any => true)
...

Any assessment on whether and how this would be possible, would be very appreciated.

Most helpful comment

@sutherland007 In your scenario the field name should be genres_name_in, genres_name_cont, or genres_name_eq. My guide is based on the simplest scenario possible, when tags are serialized on a model field of the same class; in your app acts_as_taggable_on stores the tag in a name attribute of the Genre model, and ransack has to know it has to traverse the has_many :genres association and use the name field for searching. See the ransack Readme section on associations for a deeper explanation. I'm sorry if my guide confused you.

All 15 comments

:+1:

Is there any walkaround for this? I need to filter out by skills and moods and interests all done with acts_as_taggable _on....

I need to make some hack to deal with it. I Hope i could be improved.

In my controller (I have inherited resources) :

  def collection
    ransack_params = params[:q]
    # Hack to delete params can't be used by ransack
    tag_search = ransack_params["tag_search"].split(",") if ransack_params.present? && ransack_params["tag_search"].present?
    ransack_params.delete("tag_search") if ransack_params.present?

    select_time_tables = tag_search ? referential.time_tables.tagged_with(tag_search, :any => true) : referential.time_tables
    @q = select_time_tables.search(ransack_params)
    @time_tables ||= @q.result(:distinct => true).order(:comment).paginate(:page => params[:page])
  end

In my model :

  def self.ransackable_attributes auth_object = nil
    (column_names + ['tag_search']) + _ransackers.keys
  end

You can add it by association, f.e.:

class Person < ActiveRecord::Base
   PERSON_SEARCH_OPTIONS = :name_or_email_or_tags_name_cont
end

It works for me

I think it is the better way to do it.

The answer from @norato above worked well, but I found I didn't need to add anything to the model, just the view. This worked for my recipes page (index.html.erb):

<%= search_form_for(@search) do |f| %>
  <%= f.search_field :title_or_ingredients_or_tags_name_cont %>
  <%= f.submit %>
<% end %>

@dominiceden I just created this constant in model, the functionality is the same. I did it 'cause we use a lot of custom searches in this page so we prefered to create as constants :-)

The problem with @norato solution is that you have the following tags: ['tag', 'tag_longer', 'tag_even_longer'], when your search key is 'tag' it will also find items tagged with 'tag_longer' and 'tag_even_longer'. Using _eq instead of _cont will only find elements with just one tag, so it's not a viable solution. Right now the only way I've found to perform a search with correct results is using the tagged_with helper from acts_as_taggable_on, but I have yet to find a way to put that into a Ransack search_form_for block.

EDIT: I've found a solution - use _in instead of _eq or _cont. It appears to work as expected. Great!

@metalelf0 Any chance to document your findings in the Wiki?

Sure. Here's the link: https://github.com/activerecord-hackery/ransack/wiki/How-to-search-on-ActsAsTaggableOn-fields. Let me know if it's ok. :)

@metalelf0 I've tried the wiki link and it throws "undefined method" this is my case:

in my model:

class Movie < ActiveRecord::Base
  acts_as_taggable_on :genres
end

in my view:

<%= search_form_for [:my_namespace, @q] do |f| %>
  <%= f.search_field :genres_in %> genres_in _eq or _cont throws "undefined method for #<Ransack::Search:0xaf45c20>" 
  <%= f.submit %>
<%= end %>

I'm using ruby 2.2.4, rails 4.2.6 and ransack 1.8.3

@sutherland007 if you don't mind uploading your app on github I'll download it and give it a try. Feel free to contact me on gitter.

@metalelf0 this is the app feel free to test it.

@sutherland007 In your scenario the field name should be genres_name_in, genres_name_cont, or genres_name_eq. My guide is based on the simplest scenario possible, when tags are serialized on a model field of the same class; in your app acts_as_taggable_on stores the tag in a name attribute of the Genre model, and ransack has to know it has to traverse the has_many :genres association and use the name field for searching. See the ransack Readme section on associations for a deeper explanation. I'm sorry if my guide confused you.

@metalelf0 Thanks, i think you need to update your guide using this little experience with my app. So I must say thatacts_as_taggable_on is now working well with ransack.

Was this page helpful?
0 / 5 - 0 ratings