pat/gutentag

Searching tags with Ransack

NicWickman opened this issue · 12 comments

I think this would be a common desire, so I'm posting here with my trouble. I'm loving how simple Gutentag is, adding tags is no problem. But I would like to search through them with Ransack.

Whether by adding tag_names or tags_as_string as a ransackable_attribute, I get a undefined method type' for nil:NilClass` error.

How can I return a proper tag attribute for Ransack to search for? Could you provide instructions for getting Gutentag to work with Ransack?

pat commented

Hi Nic,

I'm not familiar with Ransack, but from a quick look through its README suggests an attribute like "tags_name" might do the trick? i.e. referring to the underlying association and column. Do let me know if it works :)

Thank you for such a quick reply!

Unfortunately I am getting the same error.

pat commented

I'm a little short on context here because of not knowing Ransack well. Can you share the code you're using to try this with? i.e. is it in the form? The controller?

I am searching from a view with Ransack's seach_form_for:
<%= f.text_field :title_or_content_or_tag_names_cont, placeholder: params.dig(:q, :title_or_content_or_tag_names_cont) %>

and in the controller, which throws the error:
@resources = @q.result(distinct: true).paginate(:page => params[:page])

to define ransack's searchable parameters, I add tag_names as a "ransackable parameter" in the model

  def self.ransackable_attributes(auth_object = nil)
      ['title','content','tag_names']
  end
pat commented

I think it needs to be tags_name - with the pluralisation on the association (tags), not the column (name).

Sorry for the confusion, I've tried that as well. Not sure exactly how useful this is to you since you are not familiar with Ransack (thank you for trying regardless!), the error occurs here:

ransack (1.8.8) lib/ransack/adapters/active_record/context.rb:34:in type_for' ransack (1.8.8) lib/ransack/nodes/attribute.rb:35:in type'

          return ransacker.type
        else
          context.type_for(self)
        end
      end

If I search for an attribute which I know exists ("ID", for example) I do not get this error, so I am confident my implementation is not wrong.

PS: It's late in my timezone, I'll check back tomorrow :)

pat commented

Hmm. What about tags.name (full stop instead of underscore)? Also, you may want to add includes(:tags) to your call?

@resources = @q.result(distinct: true).includes(:tags).paginate(:page => params[:page])

No luck. search_form_for won't take tags.name

pat commented

Sorry, I really should have been more specific. Does putting it in ransackable_attributes work?

Hi Pat! A kind soul on stackoverflow knew how to make this work, I'll quote him below for yourself and anyone who wanders here.

This happens because there is no column tag_names in your table. Thus you need to define ransackable_attributes for gutentag_tags table, because that is the table whose name column is called under the hood. Create an initializer for gutentag in config/initializers directory, name it however you like. In that initializer put the following:

 if ActiveRecord::Base.connection.table_exists? 'gutentag_tags'
   model =  Object.const_get "Gutentag::Tag"
   model.singleton_class.class_eval do
     define_method(:ransackable_attributes) do |auth_object|
       auth_object = nil
       ['name']
     end
   end
 end
pat commented

Ah, great to know you got it figured out, and thanks for sharing the solution!