【问题标题】:Ransack, find record that has all related recordsRansack,查找包含所有相关记录的记录
【发布时间】:2016-02-19 10:40:59
【问题描述】:

我有一个配方模型,它有_许多成分,每种成分都属于一个项目。在我的高级搜索表单中,我希望用户选择多种成分并让 Ransack 找到包含用户选择的所有成分的食谱。

我尝试了以下搜索字段:

= f.collection_select(:ingredients_item_id_in, Item.all, :id, :name, {}, {multiple: true})

但从逻辑上讲,这会导致显示包含任何选定成分的所有食谱。

:ingredients_item_id_in 更改为:ingredients_item_id_in_all 会导致查询不正确,因为一条记录不能包含多个 item_id 值。

关于在 Ransack 中创建此搜索参数的任何想法,或者我应该为此创建一个子查询吗?

根据要求,我的控制器搜索方法:

  def search
    @q = Recipe.ransack(params[:q])
    @recipes = @q.result(distinct: true).include_related_models.published
  end

【问题讨论】:

  • 能否提供处理搜索查询的控制器方法?
  • 添加了相关代码,但是很简单..
  • 如果您想知道,include_related_models 只是一个命名范围,它定义了(相当长的)includes()
  • 你见过这个问题吗:stackoverflow.com/questions/13409627/…?似乎有点相似,认为那里的 OP 使用了不同的表单助手
  • 不,我没有,我已经执行了多次搜索,但没有遇到那个。那时(被洗劫)似乎是不可能的......不幸的是。

标签: ruby-on-rails ransack


【解决方案1】:

我最近在我的项目中遇到了类似的任务(Rails 4.2.4 / Ruby 2.3.1)。

庄园有很多舒适。我需要获得所有庄园,包括所有选定的舒适设施。

这是我使用Ransack解决它的方法

就我而言,我有has_many :through 关系。

estate.rb

class Estate < ActiveRecord::Base
  has_many :estate_comforts
  has_many :comforts, through: :estate_comforts
end

comfort.rb

class Comfort < ActiveRecord::Base
  has_many :estate_comforts
  has_many :estates, through: :estate_comforts
end

estate_comfort.rb

class EstateComfort < ActiveRecord::Base
  belongs_to :estate
  belongs_to :comfort
end

对于复杂的查询,您需要通过post 进行搜索。为此,您必须像这样编辑路线。并将search 操作添加到estates_controlle.rb。欲了解更多信息,请阅读 Ransack wiki

routes.rb

...
resources :estates
  collection do
    match 'search' => 'estates#search', via: %i[get post], as: :search
  end
end

estates_controller.rb

class EstatesController < ApplicationController
  ...

  def index
    @q = Estate.ransack(params[:q])

    @estates =
      if params[:q]&.has_key?(:estate_comforts_comfort_id_eq_any)
        # Store checked comforts
        session[:estate_comforts_comfort_id_eq_any] = params[:q][:estate_comforts_comfort_id_eq_any]

        comforts_count = params[:q][:estate_comforts_comfort_id_eq_any].count
        ids = @q.result.includes(:estate_comforts).group_by(&:id).select { |_, v| v.count == comforts_count}.keys
        Estate.where(id: ids)
      else
        @q.result(distinct: true)
      end
  end

  def search
    index
    render :index
  end
end

最后是模板部分...

estates/index.haml

= search_form_for @q, url: search_estates_path, html: { method: :post } do |f|
  # here goes the form inputs

  # Polulate checkboxes with previously checked comforts 
  - Comfort.find_each do |comfort|
    # Was checked previously?
    - checked = comfort.id.to_s.in?(session[:estate_comforts_comfort_id_eq_any].to_a)
    %div  
      %input{ name: 'q[estate_comforts_comfort_id_eq_any][]',
              type: "checkbox",
              id: "checkbox#{comfort.id}",
              value: comfort.id,
              checked: checked }
        %label{for: "checkbox#{comfort.id}"}= comfort.name

会生成下面的html

<form class="estate_search" id="estate_search" action="/estates/search" accept-charset="UTF-8" method="post">
  <div>
    <input checked="" id="checkbox1" name="q[estate_comforts_comfort_id_eq_any][]" type="checkbox" value="1">
    <label for="checkbox1">Comfort Name 1</label>
  </div>
  <div>
    <input id="checkbox2" name="q[estate_comforts_comfort_id_eq_any][]" type="checkbox" value="2">
    <label for="checkbox2">Comfort Name 2</label>
  </div>
</form>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-04
    • 1970-01-01
    • 2013-06-04
    • 2019-06-27
    • 2015-05-01
    • 2011-10-23
    • 1970-01-01
    相关资源
    最近更新 更多