使用 select 选项创建高级搜索,包括 acts_as_taggable 标签搜索

Creating advanced search with select options including acts_as_taggable tags search

我目前正在重建搜索功能,我们有一个基本搜索和一个高级搜索,我有一个基本的搜索表单,但是,我似乎无法使用基于选项的搜索.

这是我目前所拥有的。

场景:

我需要能够 select 下拉选项,然后输入我的搜索词,这是我的表单的样子

我的表格是这样的

<%= form_tag contacts_path, method: :get do %>
  <div class='l-inline-row-block'>
    <div class='l-inline-col'>
      <%= select_tag(:qs, options_for_select(['name', 'customers', 'suppliers', 'tags'], selected: params[:qs])) %>
    </div>

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

    <div class='l-inline-col'>
      <%= submit_tag submit_text, { class: 'no_print' } %>
    </div>
  </div>
<% end %>

我在控制器索引方法中有以下内容

 @contacts = Contact.search(params[:qs], params[:search])

以及模型中的以下内容

SEARCHABLE_FIELDS = [
  'name',
  'customers_name',
  'suppliers_name',
  'tags'
]

def self.search(field, query)
  if field.present? && query.present? && SEARCHABLE_FIELDS.include?(field)
    where(arel_attribute(field).matches("%#{query}%"))
  else
    all
  end
end

这是数据库结构:

  create_table "contacts", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
    t.integer  "customer_account_id"
    t.integer  "supplier_account_id"
    t.string   "name"
    t.string   "salutation"
    t.string   "title"
    t.string   "phone"
    t.string   "mobile"
    t.string   "business_email"
    t.string   "private_email"
    t.date     "date_of_birth"
    t.string   "spouse"
    t.string   "address_1"
    t.string   "address_2"
    t.string   "address_3"
    t.string   "address_4"
    t.string   "postcode"
    t.text     "other_information",   limit: 65535
    t.integer  "created_by"
    t.integer  "updated_by"
    t.string   "contact_type"
    t.integer  "assigned_to"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "company_name"
    t.string   "web_address"
    t.string   "second_phone"
    t.integer  "prospect_strength"
    t.boolean  "obsolete"
    t.string   "url"
    t.index ["obsolete"], name: "index_contacts_on_obsolete", using: :btree
  end

create_table "accounts", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
  t.string   "short_name",        limit: 9
  t.string   "name"
  t.string   "type"
  t.string   "child_type"
  t.integer  "parent_id"
  t.integer  "position"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.decimal  "value",                       precision: 11, scale: 2, default: "0.0"
  t.boolean  "fixed",                                                default: false
  t.boolean  "allow_new_child",                                      default: false
  t.integer  "created_by"
  t.integer  "updated_by"
  t.boolean  "disabled",                                             default: false
  t.boolean  "locked",                                               default: false
  t.boolean  "restricted",                                           default: false
  t.string   "account_section"
  t.string   "description"
  t.boolean  "is_budget_account",                                    default: true
  t.boolean  "is_budget_enabled",                                    default: false
  t.integer  "sequence"
  t.index ["type"], name: "index_accounts_on_type", using: :btree
end

正在使用 acts_as_taggable 作为需要可搜索的标签。

如果有帮助的话,这是之前搜索使用的当前方法

def quick_search_fields
  @quick_search_fields = [
    {
      col_name: 'name',
      title: 'name',
      column_names: ['contacts.name']
    },
    {
      col_name: 'customer_name',
      title: 'customer',
      search_tables: [:customer],
      column_names: ['accounts.name']
    },
    {
      col_name: 'supplier_name',
      title: 'supplier',
      search_tables: [:supplier],
      column_names: ['accounts.name']
    },
    {
      col_name: 'tags',
      title: 'tags',
      tags: true,
      tagged: Contact
    }
  ]
end

这是我遇到的错误:

Mysql2::Error: Unknown column 'contacts.customers' in 'where clause': SELECT  `contacts`.* FROM `contacts` WHERE (`contacts`.`suppliers` LIKE '%john%') ORDER BY id asc LIMIT 20 OFFSET 0

高级搜索选项卡看起来像这样,我尽可能不使用 gem,因为我想了解如何最好地做到这一点,显然有很多选项,但我想现在专注于基于选项的基本搜索。

谢谢。

似乎 SEARCHABLE_FIELDS 只是一个数组是不够的 您正在搜索 Contact,而其他字段在其他 table 中,例如在您搜索 supplier 时的旧搜索中,如果查找 supplier_nameaccounts.name(这里不太确定)但在供应商内部 table

    {
      col_name: 'supplier_name',
      title: 'supplier',
      search_tables: [:supplier],
      column_names: ['accounts.name']
    },

您当前的实现仅在联系人 table 中搜索,它没有 suppliers_name 也没有 customer_name 直接
现在你可以有一个解决方法,但它需要与 quick_search_fields

中的信息类似的信息

joins 联系人中的供应商 table Contact.joins(:supplier_account).where(supplier_account(s): { supplier_name: query })

------------ 更新:

首先,视图中的字段与模型中使用的字段之间存在一些不一致的地方

所以让我们将所有字段详细信息放入模型中

型号: 我假设您的模型在 customer_account_idsupplier_account_id 之间正确设置了关联

QUICK_SEARCH_FIELDS = {
    name: {
      column_names: 'contacts.name'
    },
    customers: {
        joins_table: :customer,
        column_names: 'accounts.name' # you may need to change this to association name not really sure (e.g: `customers.name`)
    },
    suppliers: {
        joins_table: :supplier,
        column_names: 'accounts.name' # here too
    },
    tags: {
      tagged_with: true
    }
}.with_indifferent_access


def self.search(field, query)
  field = QUICK_SEARCH_FIELDS[field]
  return all unless field && query

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

注意:我不明白标签的作用或你想用标签做什么所以我把它留了下来希望你能明白

在您看来,让我们直接重用模型中定义的字段以避免任何不匹配

      <%= select_tag(:qs, options_for_select(Contact::QUICK_SEARCH_FIELDS.keys(), selected: params[:qs])) %>