搜索多个模型 searchkick

如何解决搜索多个模型 searchkick

预期结果:

我想要两件事:

  1. 在我的聚合链接列表中,我希望能够添加物业特征(例如,带阳台的物业)、物业类型(例如,别墅、公寓、单间公寓等)和物业状况(例如,新的、新装修、在建等)。
  2. 在我的搜索表单中,我想要一个选择框/单选按钮,用于特征、属性类型和条件,它 (1) 显示数据库中可用项目的集合,以及 (2) 当我选择一个项目并搜索时具有该特征/属性类型/条件的所有属性

实际结果:

选择属性类型(如villa),无论属性类型如何,我都得到了所有属性。条件和特征相同。

使用 searchkick gem 的聚合功能,我也无法显示属性类型、条件或特征的聚合。

searchkick 的文档中,他们谈到它能够搜索多个模型,但是当我在控制器中尝试时,我得到的是错误

enter image description here

配置

我有一个 rails 应用程序 (v6.1.0),它有一个 Property(属于 property_type、condition 并且有很多特征到characteristic_properties)、PropertyType(has_many 属性)、Condition (has_many properties) 和 Characteristic (has_many properties thrucharacteristic_properties) 模型,我已经通过 searchkick gem 实现了弹性搜索

从那时起,我在属性属性的 seachkick 聚合的帮助下添加内容,并添加一个 Google 地图,该地图显示属性在地图上的位置。最后,我用 Pagy gem 添加分页。考虑到这一点,这就是 #indexproperties_controller.rb

中的样子
def index
args = {}
args[:surface_plot] = {}
args[:surface_plot][:gte] = params[:surface_plot_min] if params[:surface_plot_min].present?
args[:surface_plot][:lte] = params[:surface_plot_max] if params[:surface_plot_max].present?
args[:q_bathrooms] = {}
args[:q_bathrooms][:gte] = params[:q_bathrooms_min] if params[:q_bathrooms_min].present?
args[:q_bathrooms][:lte] = params[:q_bathrooms_max] if params[:q_bathrooms_max].present?
args[:q_bedrooms] = {}
args[:q_bedrooms][:gte] = params[:q_bedrooms_min] if params[:q_bedrooms_min].present?
args[:q_bedrooms][:lte] = params[:q_bedrooms_max] if params[:q_bedrooms_max].present?
args[:q_bedrooms] = params[:q_bedrooms] if params[:q_bedrooms].present?
args[:region] = params[:region] if params[:region].present?
args[:characteristics] = params[:characteristics] if params[:characteristics].present?
args[:buy] = params[:buy] if params[:buy].present?
args[:rent] = params[:rent] if params[:rent].present?
args[:share] = params[:share] if params[:share].present?
args[:floor] = {}
args[:floor][:gte] = params[:floor_min] if params[:floor_min].present?
args[:floor][:lte] = params[:floor_max] if params[:floor_max].present?
args[:floor] = params[:floor] if params[:floor].present?
args[:surface_interior] = {}
args[:surface_interior][:gte] = params[:surface_interior_min] if params[:surface_interior_min].present?
args[:surface_interior][:lte] = params[:surface_interior_max] if params[:surface_interior_max].present?
args[:sell_price] = {}
args[:sell_price][:gte] = params[:sell_price_from] if params[:sell_price_from].present?
args[:sell_price][:lte] = params[:sell_price_to] if params[:sell_price_to].present?
args[:sell_price][:gte] = params[:sell_price_min] if params[:sell_price_min].present?
args[:sell_price][:lte] = params[:sell_price_max] if params[:sell_price_max].present?
price_ranges = [{ to: 150000 },{from: 150000,to: 300000},{from: 300000,to: 500000},{from: 500000,to: 1000000},{from: 1000000}]

@properties = if params[:l]

              sw_lat,sw_lng,ne_lat,ne_lng = params[:l].split(",")

              Property.search("*",page: params[:page],per_page: 9,where: {
                                  location: { top_left: {
                                      lat: ne_lat,lon: sw_lng
                                    },bottom_right: {
                                      lat: sw_lat,lon: ne_lng
                                    }
                                  }
                                },aggs: {
                                  region: {},buy: {},rent: {},share: {},sell_price: { ranges: price_ranges },q_bedrooms: {},surface_interior: {},floor: {},characteristics: {},surface_plot: {},q_bathrooms: {}
                                })
            elsif params[:near]
              # Property.near(params[:near]).page(params[:page]).per(9)

              location = Geocoder.search(params[:near]).first
              Property.search "*",where: {
                location: {
                  near: {
                    lat: location.latitude,lon: location.longitude
                  },within: "10mi"
                }
              },aggs: {
                region: {},q_bathrooms: {}
              }
            else
              # byebug
              @query = params[:q].presence || "*"
              @properties = Searchkick.search @query,models: [Property,PropertyType],where: args,aggs:  {
                region: {},q_bathrooms: {}
              }
            end

  @pagy = Pagy.new_from_searchkick(@properties,link_extra: 'data-remote="true"')
end

这就是property.rb的样子

class Property < ApplicationRecord
  searchkick locations: [:location]
  Pagy::SEARCHKICK
  geocoded_by :address
  after_validation :geocode,if: :address_changed?
  has_many_attached :photos
  belongs_to :property_type
  belongs_to :condition
  has_many :characteristic_properties
  has_many :characteristics,through: :characteristic_properties
  has_many :viewings,dependent: :destroy
  has_many :users,through: :viewings
  belongs_to :user


  def address
   [street,city,zip_code].compact.join(",")
  end

  def address_changed?
   street_changed? || city_changed? || zip_code_changed?
  end

  def search_data
    attributes.merge location: { lat: latitude,lon: longitude }
  end
end

这是我在属性结果页面上的搜索表单:

<%= form_with url: properties_path,method: :get do |f| %>
  <!-- Price -->
  <div data-controller="menu" class="relative inline-block text-left p-0.5">
    <div data-action="click->menu#toggle">
      <button type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500" id="options-menu" aria-expanded="true" aria-haspopup="true">
        Price
        <!-- Heroicon name: solid/chevron-down -->
        <svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
          <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
        </svg>
      </button>
    </div>

  <!--
  Dropdown menu,show/hide based on menu state.

  Entering: "transition ease-out duration-100"
    From: "transform opacity-0 scale-95"
    To: "transform opacity-100 scale-100"
  Leaving: "transition ease-in duration-75"
    From: "transform opacity-100 scale-100"
    To: "transform opacity-0 scale-95"
-->
  <div data-menu-target="toggleable" class="hidden z-10 origin-top-left absolute left-0 mt-2 max-w-sm w-64 py-4 px-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
    <div class="py-1" role="none">
       <div class="flex flex-col">
          <div>
             <%= f.label :sell_price_min,"Price Range",class: "mx-1" %>
          </div>
          <div class="flex">
            <%= f.select :sell_price_min,[["No Min",""],["100mil€","100000"],["130mil€","130000"],["150mil€","150000"],["200mil€","200000"],["250mil€","250000"],["300mil€","300000"],["350mil€","350000"],["400mil€","400000"],["450mil€","450000"],["500mil€","500000"],["550mil€","550000"],["600mil€","600000"],["650mil€","650000"],["700mil€","700000"],["750mil€","750000"],["800mil€","800000"],["850mil€","850000"],["900mil€","900000"],["1M€","1000000"],["1.25M€","1250000"],["1.5M€","1500000"],["1.75M€","1750000"],["2M€","2000000"],["2.25M€","2250000"],["2.5M€","2500000"],["2.75M€","2750000"],["3M€","3000000"],["3.5M€","3500000"],["4M€","4000000"],["5M€","5000000"],["10M€","10000000"],["20M€","20000000"]],{},{ class: "mx-1 mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md",onchange: "this.form.dispatchEvent(new Event('submit',{bubbles: true}))" } %>
            <%= f.select :sell_price_max,[["No Max",{bubbles: true}))" } %>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- bedrooms -->
  <div data-controller="menu" class="relative inline-block text-left p-0.5">
    <div data-action="click->menu#toggle">
      <button type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500" id="options-menu" aria-expanded="true" aria-haspopup="true">
    bedrooms
       <!-- Heroicon name: solid/chevron-down -->
       <svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
         <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
       </svg>
     </button>
   </div>

<!--
  Dropdown menu,show/hide based on menu state.

  Entering: "transition ease-out duration-100"
    From: "transform opacity-0 scale-95"
    To: "transform opacity-100 scale-100"
  Leaving: "transition ease-in duration-75"
    From: "transform opacity-100 scale-100"
    To: "transform opacity-0 scale-95"
-->
   <div data-menu-target="toggleable" class="hidden z-10 origin-top-left absolute left-0 mt-2 max-w-sm w-64 py-4 px-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
     <div class="py-1" role="none">
       <div class="flex flex-col">
         <div>
           <%= f.label :q_bedrooms_min,"bedrooms",class: "mx-1" %>
         </div>
         <div class="flex">
           <%= f.select :q_bedrooms_min,[["All beds",["1+","1"],["2+","2"],["3+","3"],["4+","4"],["5+","5"]],{bubbles: true}))" } %>
         </div>
       </div>
    </div>
  </div>
</div>

<!-- Region -->
<div data-controller="menu" class="relative inline-block text-left p-0.5">
  <div data-action="click->menu#toggle">
    <button type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500" id="options-menu" aria-expanded="true" aria-haspopup="true">
      Region
      <!-- Heroicon name: solid/chevron-down -->
      <svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
        <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
      </svg>
    </button>
  </div>

<!--
  Dropdown menu,show/hide based on menu state.

  Entering: "transition ease-out duration-100"
    From: "transform opacity-0 scale-95"
    To: "transform opacity-100 scale-100"
  Leaving: "transition ease-in duration-75"
    From: "transform opacity-100 scale-100"
    To: "transform opacity-0 scale-95"
-->
  <div data-menu-target="toggleable" class="hidden z-10 origin-top-left absolute left-0 mt-2 max-w-sm w-64 py-4 px-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
    <div class="py-1" role="none">
      <div class="flex flex-col">
        <div>
          <%= f.label :region,"Region",class: "mx-1" %>
        </div>
        <div class="flex">
          <%= f.select :region,@properties.aggs["region"]["buckets"].sort_by { |b| b["key"] }.collect { |bucket| bucket["key"] },{ include_blank: "All Regions",selected: "All Regions" },{bubbles: true}))" } %>
         </div>
      </div>
    </div>
  </div>
</div>

<!-- More -->
<div data-controller="menu" class="relative inline-block text-left p-0.5">
  <div data-action="click->menu#toggle">
    <button type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500" id="options-menu" aria-expanded="true" aria-haspopup="true">
    More
      <!-- Heroicon name: solid/chevron-down -->
      <svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
      <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
      </svg>
    </button>
  </div>

<!--
  Dropdown menu,show/hide based on menu state.

  Entering: "transition ease-out duration-100"
    From: "transform opacity-0 scale-95"
    To: "transform opacity-100 scale-100"
  Leaving: "transition ease-in duration-75"
    From: "transform opacity-100 scale-100"
    To: "transform opacity-0 scale-95"
-->
    <div data-menu-target="toggleable" class="hidden z-10 origin-top-left absolute left-0 mt-2 max-w-sm w-96 py-4 px-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
      <div class="py-1" role="none">
        <div class="flex flex-col">
          <div class="py-2">
            <div class="flex justify-center py-2">
            <!-- radio_button(object_name,method,tag_value,options = {}) public -->
            <!-- This example requires Tailwind CSS v2.0+ -->
              <div class="flex justify-center">
                <span class="relative z-0 inline-flex shadow-sm rounded-md">
                  <% if params[:buy] == "true" %>
                    <%= link_to "Buy",request.params.except(:buy),id: "type",class: "relative inline-flex items-center px-3 py-2 rounded-l-md border border-gray-300 text-sm font-medium focus:z-10 focus:outline-none focus:border-white focus:bg-blue-500 focus:text-white hover:no-underline text-white bg-blue-500 duration-300 ease-in-out" %>
                  <% else %>
                    <%= link_to "Buy",request.params.merge(buy: true),class: "relative inline-flex items-center px-3 py-2 rounded-l-md border border-gray-300 text-sm font-medium focus:z-10 focus:outline-none focus:border-white focus:bg-blue-500 focus:text-white hover:no-underline hover:text-white hover:bg-blue-500 duration-300 ease-in-out" %>
                  <% end %>
                  <% if params[:rent] == "true" %>
                    <%= link_to "Rent",request.params.except(:rent),class: "-ml-px relative inline-flex items-center px-3 py-2 border border-gray-300 text-sm font-medium  focus:z-10 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 hover:no-underline text-white bg-blue-500 duration-300 ease-in-out" %>
                  <% else %>
                    <%= link_to "Rent",request.params.merge(rent: true),class: "-ml-px relative inline-flex items-center px-3 py-2 border border-gray-300 text-sm font-medium  focus:z-10 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 hover:no-underline hover:text-white hover:bg-blue-500 duration-300 ease-in-out" %>
                  <% end %>
                  <% if params[:share] == "true" %>
                    <%= link_to "Share",request.params.except(:share),class: "-ml-px relative inline-flex items-center px-3 py-2 rounded-r-md border border-gray-300 text-sm font-medium  focus:z-10 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 hover:no-underline text-white bg-blue-500 duration-300 ease-in-out" %>
                   <% else %>
                    <%= link_to "Share",request.params.merge(share: true),class: "-ml-px relative inline-flex items-center px-3 py-2 rounded-r-md border border-gray-300 text-sm font-medium  focus:z-10 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 hover:no-underline hover:text-white hover:bg-blue-500 duration-300 ease-in-out" %>
                   <% end %>
                </span>
              </div>
            </div>
          </div>
          <div class="py-2">
            <div>
              <%= f.label :floor_min,"Floor",class: "mx-1" %>
            </div>
            <div class="flex">
              <%= f.select :floor_min,[["All Floors",["1st floor and up",["2nd floor and up",["3rd floor and up",["4th floor and up",["5th floor and up",{bubbles: true}))" } %>
            </div>
          </div>
          <div class="py-2">
            <div>
              <%= f.label :surface_interior_min,"Interior Surface",class: "mx-1" %>
            </div>
            <div class="flex">
              <%= f.number_field :surface_interior_min,value: params[:surface_interior_min],placeholder: "Min",{bubbles: true}))",class: "w-full rounded m-1" %>
              <span class="flex items-center"> - </span>
              <%= f.number_field :surface_interior_max,value: params[:surface_interior_max],placeholder: "Max",class: "w-full rounded m-1" %>
            </div>
          </div>
          <div class="py-2">
            <div>
              <%= f.label :surface_plot_min,"Size Plot",class: "mx-1" %>
            </div>
            <div class="flex">
              <%= f.select :surface_plot_min,["150m²+","150"],["200m²+","200"],["250m²+","250"],["300m²+","300"],["350m²+","350"],["400m²+","400"],["450m²+","450"],["500m²+","500"],["1000m²+","1000"],["1500m²+","1500"],["2000m²+","2000"],["2500m²+","2500"],["3000m²+","3000"],["3500m²+","3500"],["4000m²+","4000"],["4500m²+","4500"],["5000m²+","5000"],["6000m²+","6000"],["7000m²+","7000"],["8000m²+","8000"],["9000m²+","9000"],["1ha+","10000"],["2ha+","20000"]],{bubbles: true}))" } %>
            </div>
          </div>
          <div class="py-2">
            <div>
              <%= f.label :q_bathrooms_min,"Bathrooms",class: "mx-1" %>
            </div>
            <div class="flex justify-center py-2">
              <!-- radio_button(object_name,options = {}) public -->
              <!-- This example requires Tailwind CSS v2.0+ -->
              <span class="relative z-0 inline-flex shadow-sm rounded-md">
                <button type="button" class="bathroom-btn relative inline-flex items-center px-4 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:bg-blue-500 focus:text-white hover:no-underline hover:text-white hover:bg-blue-500 duration-300 ease-in-out">
                  <%= f.radio_button :q_bathrooms_min,"",class: "absolute transform scale-0" %>
                  <%= f.label :q_bathrooms_min_1,"Any",class: "cursor-pointer" %>
                </button>
                <button type="button" class="bathroom-btn -ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:bg-blue-500 focus:text-white hover:no-underline hover:text-white hover:bg-blue-500 duration-300 ease-in-out">
                  <%= f.radio_button :q_bathrooms_min,"1","1+","2",class: "absolute transform scale-0" %>
                  <%= f.label :q_bathrooms_min_2,"2+",class: "cursor-pointer" %>
                </button>

                <button type="button" class="bathroom-btn -ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:bg-blue-500 focus:text-white hover:no-underline hover:text-white hover:bg-blue-500 duration-300 ease-in-out">
                  <%= f.radio_button :q_bathrooms_min,"3",class: "absolute transform scale-0" %>
                  <%= f.label :q_bathrooms_min_3,"3+","4",class: "absolute transform scale-0" %>
                  <%= f.label :q_bathrooms_min_4,"4+",class: "cursor-pointer" %>
                </button>
                <button type="button" class="bathroom-btn -ml-px relative inline-flex items-center px-4 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:bg-blue-500 focus:text-white hover:no-underline hover:text-white hover:bg-blue-500 duration-300 ease-in-out">
                  <%= f.radio_button :q_bathrooms_min,"5",class: "absolute transform scale-0" %>
                  <%= f.label :q_bathrooms_min_5,"5+",class: "cursor-pointer" %>
                </button>
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
<% end %>

我已经为此苦苦挣扎了一段时间。我希望有人可以帮助我。我会很感激的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?