【问题标题】:Creating advanced search with select options including acts_as_taggable tags search使用包括acts_as_taggable标签搜索在内的选择选项创建高级搜索
【发布时间】:2021-07-04 04:43:58
【问题描述】:

我目前正在重新构建搜索功能,我们有一个基本搜索和一个高级搜索,我有一个基本搜索表单正在工作,但是,我似乎无法让基于选项的搜索工作。

这是我目前所拥有的。

场景:

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

我的表单是这样的

<%= 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,因为我想学习如何最好地做到这一点,显然有很多选项,但我想专注于基于基本选项现在搜索。

谢谢。

【问题讨论】:

    标签: ruby forms activerecord ruby-on-rails-5 rails-activerecord


    【解决方案1】:

    看来SEARCHABLE_FIELDS 只是一个数组是不够的 您正在搜索 Contact 仅当其他字段在其他表中时,例如在您搜索 supplier 时的旧搜索中,如果查找 supplier_nameaccounts.name(此处不太确定)但在供应商表中

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

    您当前的实现只是在没有suppliers_namecustomer_name 的联系人表中直接搜索
    现在您可以找到解决方法,但它需要与 quick_search_fields 中的信息类似的信息

    你在哪里joins联系人表上的供应商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])) %>
    

    【讨论】:

    • 那么可以重复使用quick_search_fields吗?关于那个连接,虽然它会去哪里,根据我上面的代码,你是否有可能更多地充实这个例子。试图了解这将如何工作,因为这是我正在开发的旧版应用程序,因此我正在尝试使此搜索的工作方式现代化。
    • 能否请您发布供应商、客户的架构,如果有帐户表,那么也可以
    • 我已在联系人模式的同一代码块中添加了帐户表,而对于供应商和客户,没有相应的模式
    • @debugabug 我添加了一个示例,但我不明白标签是如何工作的,所以我把它省略了
    • 确实有使用acts_as_taggable,但我会尝试以下方式
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多