搜索多个字段 rails 5

Search multiple fields rails 5

我有以下表格:

<div class='panel' id='panel-advanced-search'>
  <%= form_tag contacts_path, method: :get do %>
    <div>
      <div class='advanced_search'>
        <div>
          <%= label_tag "Contact Type" %>
          <%= select_tag(:contact_type, options_for_select(Contact::TYPES, selected: params[:contact_type]), prompt: 'Any', class: 'customSelect') %>
        </div>

        <div>
          <%= label_tag "Prospect Strength" %>
          <%= select_tag(:prospect_strength, options_for_select(Contact::PROSPECT_STRENGTHS, selected: params[:prospect_strength]), prompt: 'Any', class: 'customSelect') %>
        </div>

        <div>
          <%= label_tag "Customer" %>
          <%= collection_select(:customer_account_id, :customer_account_id, Customer.order(:name), :id, :name, { prompt: '' }, class: 'customSelect select2') %>
        </div>

        <div>
          <%= label_tag "Supplier" %>
          <%= collection_select(:supplier_account_id, :supplier_account_id, Supplier.order(:name), :id, :name, { prompt: '' }, class: 'customSelect select2') %>
        </div>

        <div>
          <%= label_tag "Company Name" %>
          <%= text_field_tag :company_name %>
        </div>

        <div>
          <%= label_tag "Name" %>
          <%= text_field_tag :name %>
        </div>

        <div>
          <%= label_tag "Job Title" %>
          <%= text_field_tag :title %>
        </div>

        <div>
          <%= label_tag "Postcode" %>
          <%= text_field_tag :postcode %>
        </div>

        <div>
          <%= label_tag :created_at, 'Created From' %>

          <div class="date-picker">
            <%= text_field_tag :created_at, nil, class: 'date-picker-select' %>

            <span class="date-picker-btn">
              <span class="icon-calendar" aria-hidden="true"></span>
            </span>
          </div>
        </div>

        <div>
          <%= label_tag :updated_at, 'Created To' %>

          <div class="date-picker">
            <%= text_field_tag :updated_at, nil, class: 'date-picker-select' %>

            <span class="date-picker-btn">
              <span class="icon-calendar" aria-hidden="true"></span>
            </span>
          </div>
        </div>

        <div>
          <%= label_tag "Tags" %>
          <%= collection_select(:tag_list, :tag_list, @tags.order(:name), :name, :name, {}, { class: 'select2', multiple: true }) %>
        </div>

        <div>
          <%= label_tag "Assignee" %>
          <%= collection_select(:assigned_to, :assigned_to, User.all, :id, :name, { prompt: 'Any' }, class: 'customSelect select2') %>
        </div>

        <div>
          <%= label_tag "Obsolete?" %>
          <%= select_tag(:obsolete, options_for_select(['Obsolete', 'All'], selected: params[:obsolete]), prompt: 'Not obsolete?', class: 'customSelect') %>
        </div>

        <div>
          <%= label_tag "Send Results To" %>
          <%= select_tag(:subsequent_action, options_for_select([
            ['Report', 'report'],
            ['CSV Export', 'csv_export'],
            ['New Event', 'new_event']
          ]), prompt: 'None', class: 'customSelect') %>
        </div>
      </div>

      <div class="advanced_search_btns">
        <%= submit_tag submit_text %>
        <%= link_to secondary_btn, contacts_path, class: 'btn-medium' %>
      </div>
    </div>
  <% end %>
</div>

和模型中的以下方法

def self.advanced_search
  Contact.where('
    contact_type LIKE :search OR
    prospect_strength LIKE :search OR
    customer_account_id LIKE :search OR
    supplier_account_id LIKE :search OR
    company_name LIKE :search OR
    name LIKE :search OR
    title LIKE :search OR
    postcode LIKE :search OR
    created_at LIKE :search OR
    updated_at LIKE :search OR
    tag_list LIKE :search OR
    assigned_to LIKE :search OR
    obsolete LIKE :search
  ', search: "%#{search}%"
  )
end

我该如何着手使用此方法,以便用户可以使用带有多个参数的搜索表单?我已经在基本搜索的索引方法中有了以下内容,所以我需要同时拥有这两种搜索形式

def index
  @per_page = params[:per_page] || 20
  @tags = ActsAsTaggableOn::Tag.all

  if params[:search].present?
    @contacts = Contact.search(params[:qs], params[:search]).order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: @per_page)
  else
    @contacts = Contact.all.order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: @per_page)
  end
end

编辑 将上面的表格更新为完整的表格,理想情况下,我希望表格功能完全包含在模型中。

编辑#2

这是基本搜索:

型号

QUICK_SEARCH_FIELDS = {
  name: {
    column_names: 'contacts.name'
  },
  customers: {
    joins_table: :customer,
    column_names: 'contacts.name',
    filters: { contact_type: 'customer' }
  },
  suppliers: {
    joins_table: :supplier,
    column_names: 'contacts.name',
    filters: { contact_type: 'supplier' }
  },
  tags: {
    tagged_with: true
  }
}.with_indifferent_access

def self.search(field, query)
  field = QUICK_SEARCH_FIELDS[field]

  contact = all
  contact = contact.joins(field[:joins_table]) if field[:joins_table]
  contact = contact.where(field[:filters]) if field[:filters]
  contact = contact.where("#{field[:column_names]} LIKE ?", "%#{query}%") if field[:column_names]
  contact = contact.tagged_with(query) if field[:tagged_with]
  contact
end

形式

<div class='panel' id='panel-search'>
  <%= form_tag contacts_path, method: :get do %>
    <div class='l-inline-row-block'>
      <div class='l-inline-col width_120px'>
        <%= select_tag(:qs, options_for_select(Contact::QUICK_SEARCH_FIELDS.keys(), selected: params[:qs]), class: 'customSelect') %>
      </div>

      <div class='l-inline-col'>
        <%= search_field_tag :search, params[:search] %>
      </div>

      <div class='l-inline-col' style='width: 100px;'>
        <%= submit_tag submit_text %>
      </div>
    </div>
  <% end %>
</div>

您可能需要进行视图调整,不能只对所有字段使用 search term/query:

1.make 请确保您视图中表单内的字段与 Contact 模型中需要搜索的列的名称相同 2.add 每个表单中的一个隐藏字段,因此您可以确定这是哪个搜索(还有另一个选项,但这个选项工作较少) 3.change collection_select 其中用户只能 select 一个字段到 select_tag 为了不搞乱查询构建

每个填充的字段都会传递一个值 - 您可以构建一个散列,包括输入的 column/form-field 及其值,例如 { contact_type: "value1", prospect_strength: "value2" }

之后,您需要使用该散列构建查询并查询数据库

这看起来像这样:

在您看来:

在高级搜索表单中添加这个

<%= hidden_field_tag :search_type, :advanced %>

然后在您的正常搜索中添加这个

<%= hidden_field_tag :search_type, :normal %>

在您的模型中:

def self.advanced_search(values_by_column_name) # values_by_column_name is a hash passed from the controller
    tag_list = values_by_column_name.delete("tag_list")
    sql_query = values_by_column_name.keys.map { |column| "#{column} LIKE :#{column}" }
    sql_query = sql_query.join(" OR ")
    values_by_column_name = values_by_column_name.transform_values { |value| "%#{value}%" }.symbolize_keys

    relation = Contact.where(sql_query, values_by_column_name)
    relation = relation.tagged_with(tag_list) if tag_list
    relation
end

在你的控制器中:

ADVANCED_SEARCH_FIELDS = [
    :contact_type,
    :prospect_strength,
    :customer_account_id,
    :supplier_account_id,
    :company_name,
    :name,
    :title,
    :postcode,
    :created_at,
    :updated_at,
    {tag_list: []},
    :assigned_to,
    :obsolete,
]

def index
    @per_page = params[:per_page] || 20
    @tags = ActsAsTaggableOn::Tag.all

    if advanced_search?
        @contacts = Contact.advanced_search(advanced_search_params)
    elsif normal_search?
        @contacts = Contact.search(params[:qs], params[:search])
    else
        @contacts = Contact.all
    end

    @contacts = @contacts.order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: @per_page)
end

def advanced_search?
    params[:search_type] == "advanced" && advanced_search_params.any?
end

def normal_search?
    params[:search_type] == "normal" && params[:search].present?
end

def advanced_search_params
    @_advanced_search_params ||= params.permit(ADVANCED_SEARCH_FIELDS).select { |_, v| v.present? }.to_h
end