[RAILS] Implementation of multiple word search, multiple model search, and multiple tag search (acts-as-taggable-on) of ransack

I had a little trouble with ransack's multiple model search and multiple tag search, so I will post it as a reference for similar people.

This time, we will implement it in the case of User model, Article model, Tag model (using gem called acts-as-taggable-on). .. The search is performed (multiple words) from the text column of the article of the posted article, the name column of User, and the name column of the tag associated with User. (This time, tag is tied to User, not article)

First, on the view side, it will be as follows

articles/index.html.erb


<%= search_form_for(@search, url: articles_path) do |f| %>
  <%= f.search_field :text_or_user_name_cont_all  , class:"search_field", placeholder:"Search" %>
  <%= f.submit 'Search', id:"search_button" %>
<% end %>

This search_form_for, search_field, and cont_all are the way to write ransak. I will omit the explanation around here.

On the controller side, the scope function of ransack (ransackable_scopes) is called. The search word is passed as an argument and the search is performed on the model side of the article.

articles_controller.rb


   .
   .
@search = Article.ransack(params[:q])
  if params[:q].present? #params nil measures
    @search_articles_result = Article.by_any_texts(params[:q][:text_or_user_name_cont_all])
  end
   .
   .

article.model.rb


scope :by_any_texts, -> (string){
  words = string.split(/[\p{blank}\s]+/)
  searchs = search(text_or_user_name_cont_all: words).result(distinct: true)
  search_tag = User.by_any_tag(words).flatten
  search_result = searchs + search_tag
  search_result.uniq
}

def self.ransackable_scopes(auth_object = nil)
  %i[text_or_user_name_cont_all]
end

Split the params [: q] [: text_or_user_name_cont_all: words] passed as an argument into the form ["word1", "words2"]. After that, ransack is performed, but searching across ransack models can be easily implemented as if writing an association. In this case, if you want to search for Article text and User name, use text_or_user_name. As a way of writing, it can be implemented with the related model name (user) + column name (name). Furthermore, if you want to check the tags associated with user, you can search by text_or_user_name_or_user_tags_name. The plural form with tags is due to the one-to-many relationship between user and tag. However, I think that the implementation of the tag function this time is because the gem of acts-as-taggable-on was used, but it did not pull when doing multiple word searches. (I pulled it for one word, but I couldn't search for multiple words ...) Therefore, regarding tag, we created a scope in the User model separately and implemented it using the search function (tagged_with) of acts-as-taggable-on.

user.model.rb



scope :by_any_tag, -> (words){
  user_tag = User.tagged_with(words, named_like_any: true)
  user_tag.map{|tag| tag.articles}         
}

It receives the words split on the article side as an argument and searches for the tag associated with User. After that, the map method is used to create a new array of articles linked to the search results.

On the article side, by_any_tag is called, the two-dimensional array is flattened, and the original search result of text_or_user_name_cont_all and the search result of the tag searched on the user side are added. There may be duplicate results, so uniq and finish.

Recommended Posts

Implementation of multiple word search, multiple model search, and multiple tag search (acts-as-taggable-on) of ransack
[Rails] Implementation of tag function using acts-as-taggable-on and tag input completion function using tag-it
[Rails] Implementation of search function using gem's ransack
Implementation of search function
Implementation of sequential search function
Use ransack Search function implementation
[Rails 6] Implementation of search function
Combination of search and each_with_index
[Rails] Search from multiple columns + conditions with Gem and ransack
Default implementation of Object.equals () and Object.hashCode ()
Whereabouts of JAXB Reference implementation and DatatypeConverterImpl
Implementation of tabs using TabLayout and ViewPager