【问题标题】:Ruby on rails - adding a select tag to search different fieldsRuby on rails - 添加一个选择标签来搜索不同的字段
【发布时间】:2021-04-07 16:21:15
【问题描述】:

我正在开发一个应用的搜索功能,我有一个基本的搜索工作,但是,我需要能够有一个选择字段来选择用户搜索的内容。

即如果我有一个带有以下内容的选择标签:

姓名、货币、公司名称

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

我的表单是这样的

<%= 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[:search])

以及模型中的以下内容

def self.search(search)
  if search
    contacts = Contact.order(:id)
    contacts = contacts.where("name like ?", "%#{search}%") if search.present?
    contacts
  else
    contacts = Contact.all
  end
end

我已经查看了https://railscasts.com/episodes/111-advanced-search-form-revised,但我不需要单独的搜索页面,我需要在索引页面上进行所有搜索。

任何帮助都会很棒。

更新

我使用了@max 的以下解决方案(谢谢),但是遇到了一些其他问题:

这是数据库结构:

  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

每个联系人记录都有一个contact_type,所以不确定我们是否可以搜索到它,但需要客户和供应商选项。

使用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

这是我的select_tag &lt;%= select_tag(:qs, options_for_select(['name', 'customers', 'suppliers', 'tag_list'], selected: params[:qs])) %&gt; + max 解的变化。但是,这是我在搜索供应商、客户和标签时遇到的错误。

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

【问题讨论】:

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


    【解决方案1】:

    您需要将搜索方法的数量增加到 2,并使用动态列名构造一个 LIKE 查询:

    class Contact < ApplicationRecord
      # Prevents sql injections
      SEARCHABLE_FIELDS = ['name', 'customers', 'suppliers', 'tags']
    
      def self.search(field, query)
        if field.present? && query.present? && SEARCHABLE_FIELDS.include?(field)
          # WHERE contacts.field LIKE '%?%'
          where(arel_attribute(field).matches("%#{query}%"))
        else
          all
        end
      end
    end
    
    @contacts = Contact.search(params[:qs], params[:search])
    
    

    如果您想根据字段改变搜索执行的逻辑,我真的建议您将此功能从模型中提取到一个单独的对象中,或者查看诸如 Ransack 之类的 gem。

    见:

    【讨论】:

    • Rails 为arel_table[column] 提供了一种方便的方法,称为arel_attribute,它感觉有点不那么深奥。(它也接受StringSymbol)例如arel_attribute(field).matches("%#{query}%")
    • 我没有意识到这一点。谢谢@engineersmnky
    • 明天我会试一试,谢谢,这是我正在重建的基本搜索,我们拥有的高级搜索大约有 12 个不同的选项等,所以我希望我可以添加到上面。
    • 抱歉应该是.include?。那个总是让我绊倒,因为它是如此不合语法......
    【解决方案2】:

    如果我了解您想要实现的目标,我认为您可以像这样在控制器中完成所有操作:

    def index
      if params[:search].present?
        case params[:qs]
        when 'name'
          result = 'your query for name'
        when 'customers'
          result = 'your query for customers'
        when 'suppliers'
          result = 'your query for suppliers'
        else
          result = 'your query for tags'
        end
        result
       else
         a default query if no search
       end
    end
    

    【讨论】:

    • 明天我会试一试,谢谢,这是我正在重建的基本搜索,我们拥有的高级搜索大约有 12 个不同的选项等,所以我希望我可以添加到上面。
    猜你喜欢
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多