首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Rails 4中使用多到多的高级搜索。

在Rails 4中使用多到多的高级搜索。
EN

Stack Overflow用户
提问于 2019-04-19 15:57:57
回答 1查看 71关注 0票数 0

我有一个房地产清单,每个房地产都有一些特点。然后,我有两个桌子:

  • real_estates,存储用户添加的所有房地产。
  • re_home_features,存储管理员添加的所有默认功能,如池、壁橱、办公室、花园和房地产可以拥有的许多功能。

相同的real_estate可以有许多特性,相同的特性可以有很多房地产。我创建了这些模型:

real_estate.rb

代码语言:javascript
复制
class RealEstate < ActiveRecord::Base
    has_many :real_estate_home_features
    has_many :re_home_features, as: :home_features, through: :real_estate_home_features, dependent: :destroy
end

re_home_features.rb

代码语言:javascript
复制
class ReHomeFeature < ActiveRecord::Base
    has_many :real_estate_home_features
    has_many :real_estates, through: :real_estate_home_features
end

real_estate_home_feature.rb

代码语言:javascript
复制
class RealEstateHomeFeature < ActiveRecord::Base
    belongs_to :real_estate
    belongs_to :re_home_feature
end

有了这个关系,很多人对许多人的关系都很好。

我要搜索一些参数的房地产,比如:

  • 起居室数
  • 浴室数目
  • 售价(最低至最高)
  • 总面积(最小至最大)
  • 房地产代码
  • 还有很多其他的对立面

我的搜索是这样的:

real_estates_controller.rb

代码语言:javascript
复制
def search
    r = real_estates
    r = r.where(code: params['code']) if params['code'].present?
    r = r.where(city_name: params['city']) if params['city'].present?
    r = r.where(garage: params['garage']) if params['garage'].present?
    r = r.where(restrooms: params['restrooms']) if params['restrooms'].present?

    r = r.paginate(:page => params[:page], :per_page => 10)

    r
end

这次搜索也很顺利。这没有问题,因为所有参数都在同一个表real_estates中。

但是现在,搜索要复杂一些。我要找一些有特色的房地产。我想要所有的房地产,其中有4个卫生间,2辆汽车在车库和有

在我的例子中,在有4间洗手间和2辆车的房地产里,我找到了50个房地产,但只有15个有游泳池。

我如何过滤这50个房地产只显示与“池功能”相关的记录?

我无法在视图中验证,因为每页都会导致错误的数字。我认为筛选必须发生在数据库查询的时刻,就在分页之前。

我很感激你的帮助!

环境

代码语言:javascript
复制
rails -v: Rails 4.2.1
ruby -v: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
so: Ubuntu 16.04.5 LTS
localhost database: MySQL (development)
server database: Postgres (production)

编辑1

基于@jvillian答案,我将更改我的控制器,在查询中添加一个联接。

代码语言:javascript
复制
if params['home_features'].present? && params['home_features'].any?
    r = r.joins(:re_home_features).where(re_home_features: {id: params['home_features']}).distinct(:id)
end

在我的测试中,我有:

代码语言:javascript
复制
params['home_features'] = [1 , 2, 3]

我有一个房地产,其中有这三个特点。但是,在视图中,我看到同一个网站显示了3次。如果我加上不同的,房地产只显示一次。但是..。如果我将params改为:

代码语言:javascript
复制
params['home_features'] = [1 , 2, 3, 500]

我没有这四个功能的房地产,但结果是一样的。没有明显的差异,房地产显示3次。有了小吃,房地产就展示了一次。预期的结果是零结果,因为我想要房地产与所有选定的功能。

但我想我们快到了!我将提供一些关于我的模型的信息:

表real_estates

代码语言:javascript
复制
id | title      | description | code | city_name      | garage | ...
 7 | Your House | Awesome...  | 1234 | Rio de Janeiro | 4

表re_home_features

代码语言:javascript
复制
id | name
 1 | Pool
 2 | Garden
 3 | Tenis court
 4 | Closet

表real_estate_home_features -将多个关联起来

代码语言:javascript
复制
id | real_estate_id | re_home_feature_id
 1 |              7 |                  1
 2 |              7 |                  2
 3 |              7 |                  3

如果我跑:

代码语言:javascript
复制
r = r.joins(:re_home_features).where(re_home_features: {id: [1,2,3,500]}).distinct(:id)

我得到了以下查询(rails控制台):

代码语言:javascript
复制
SELECT DISTINCT `real_estates`.* FROM `real_estates` INNER JOIN `real_estate_home_features` ON `real_estate_home_features`.`real_estate_id` = `real_estates`.`id` INNER JOIN `re_home_features` ON `re_home_features`.`id` = `real_estate_home_features`.`re_home_feature_id` WHERE `re_home_features`.`id` IN (1, 2, 3, 500)

它返回一个结果。房地产id 7。如果我去掉不同的,我有3个结果:相同的房地产,3次。

预期结果为零。如果是params['home_features'] = [1 , 2, 3],我希望得到一个结果。

编辑2

此联接方法工作正常,但返回类似于"OR“查询。在我的例子中,我需要一个带有"AND“的联接查询。查询必须是:“返回所有具有1、2和3功能的房地产”。

Tks!

EN

回答 1

Stack Overflow用户

发布于 2019-04-19 16:24:15

我不确定这是不是“高级搜索”。在12.1.4指定联接表的条件下的指南中包含了对已连接模型的搜索。它看起来应该是:

代码语言:javascript
复制
real_estates.joins(:re_home_features).where(re_home_features: {feature_name: 'pool'})

当然,这可能不会完全奏效,因为您没有告诉我们如何找到“池功能”。但是,它应该给你正确的方向。

顺便说一下,原因是:

代码语言:javascript
复制
params['home_features'] = [1 , 2, 3, 500]

返回具有any of home_features的记录是因为它使用了“或”。如果您希望real_estates包含所有的home_features,那么您需要一个‘和’。你可以在这上面到处搜索。

我想我会尝试这样的方法:

代码语言:javascript
复制
def search

    r = real_estates.joins(:re_home_features)

    %i(
      code
      city_name
      garage
      restrooms
    ).each do |attribute|
      r = r.where(attribute => params[attribute]) unless params[attribute].blank?
    end

    params[:home_features].each do |home_feature_id|
      r = r.where(re_home_features: {id: home_feature_id})
    end unless params[:home_features].blank?

    r = r.uniq
    r = r.paginate(:page => params[:page], :per_page => 10)
    r

end

注意:我将params[:city]改为params[:city_name],以使第一个each迭代器更干净。如果你想这样做的话,你需要改变你的观点。如果您不想这样做,那么您可以回到您已经拥有的非迭代器方法。

这是没有测试的,所以我不相信它会完全按照现在的方式工作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55764534

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档