简体   繁体   中英

combine multiple search results

first, thank you for your help and support. after setup a simple search using scenic and textacular. i´ve tried to combine the results with a simple combination on the search controller. the search works very well but, if i search for tag, i got the

undefined method `username' for #Tag:0x0000

as i find out many solutions come with concatenating the query and the models are associated.

so in this case, the models are not associated. so someone can give a tip to how to combine separated models attrs in one query?

the model:

class Search < ApplicationRecord
    extend Textacular

  belongs_to :searchable, polymorphic: true
   attr_accessor :query


  def results
    if @query.present?
      self.class.search(@query).preload(:searchable).to_a.map!(&:searchable).uniq
    else
      Search.none
    end
  end

end

controller:

class SearchController < ApplicationController
respond_to :html


def index
  @users = User.search(params[:search])
  @tags = Tag.search(params[:search])
  @search_results = @users + @tags  

 if params[:search].present?
        @search_results = Search.new(query: params[:search]).results
    else
        @users = User.all
    end

  end

end

the view:

<div>
<% @search_results.each do |r| %>

<%= r.username %>
<%= r.name %>

<% end %> 

</div>

In controller you have

@users = User.search(params[:search])
@tags = Tag.search(params[:search])
@search_results = @users + @tags  

So, @users are members of User class and @tags are member of Tag class.

You are calling username attribute on @search_results , so you are doing it on @tags .

The easy fix is to use two each cycle in view, one for @users and one for @tags .

<% @users.each do |user| %>
<%= user.username %>
<% end %>

And

<% @tags.each do |tag| %>
<%= tag.name %>
<% end %>

Another fix I think should work is to alias an attribute of Tag or User like here .

In your controller action, you are first assigning values to @users and @search_results and then simply overriding either one of them without using it. So, i moved the statements a bit to remove any unused assignment of values:

class SearchController < ApplicationController
  def index
    if params[:search].present?
      @search_results = Search.new(query: params[:search]).results
    else
      @users = User.all
    end

    # Are you sure you still need to set `@users` and `@tags`? Reason: `@search_results` above would already be set if `params[:search]` was present.
    @users ||= User.search(params[:search])    # Assigns only if @users is not previously set
    @tags = Tag.search(params[:search])
    @search_results ||= @users + @tags
  end
end

Further improvement can be made if you are using only @search_results in your view and NOT @users and @tags :

class SearchController < ApplicationController
  def index
    @search_results = if params[:search].present?
                        Search.new(query: params[:search]).results
                      else
                        User.all + Tag.all
                      end
  end
end

And finally in your view:

<div>
  <% @search_results.each do |r| %>
    <% if r.respond_to?(:name) %>
      <%= r.name %>
    <% elsif r.respond_to?(:username) %>
      <%= r.username %>
    <% end %>
  <% end %> 
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM