【问题标题】:Rails 5: How to query Activerecord models in a three-level nested hierarchy?Rails 5:如何在三层嵌套层次结构中查询 Activerecord 模型?
【发布时间】:2018-03-07 19:32:36
【问题描述】:

我正在构建一个双向市场网络应用程序,用户可以在该应用程序中出售许多“优惠”。每个“报价”都可以由另一个用户(买方)购买。然后买家可以对“购买”进行评分(0 到 5 分/星)。

我的模特:

User:
has_many :offers, dependent: :destroy
has_many :purchases, dependent: :destroy

Offer:
has_many :purchases, dependent: :destroy
belongs_to :user

Purchase:
belongs_to :user
belongs_to :offer

图像表示: Image representation

问题:

我需要从数据库中获取一个用户(“卖家”),包括他/她是相关报价的卖家的所有购买,并且购买评级不为空。

我的尝试:

    @user = User.includes(offers: :purchases).
  where(offers: { user_id: params[:seller_id] }).
  where(id: params[:seller_id]).first

结果:

我在他/她是买家的地方进行采购。相反,我需要购买他/她是卖方的任何报价,并且购买评级不为空。

我还没有查询评级,因为我不知道如何将其包含在查询中。

任何见解将不胜感激。

【问题讨论】:

  • 澄清一下,Purchase#user_id 实际上是 购买的用户 IDOffer#user_id正在销售/已售出的用户 ID,对吧?
  • 如果我之前的评论是真的,那么这应该有效:User.includes(offers: :purchases).where(offers: { user_id: seller_id }).where('purchases.rating IS NOT NULL')。这意味着它将获取具有一个或多个Offer 的任何User,其中他是卖家,并且此报价具有一个或多个Purchase,且评级不为空。
  • 谢谢,您的第一条评论是真的。现在我正在这样做:@user = User.includes(offers: :purchases). where(offers: { user_id: seller_id }). where('purchases.rating IS NOT NULL').first @user 获取用户数据,但 @user.purchases 集合为空。
  • 这是因为UserPurchase 之间的关联实际上是purchaser,而不是seller 关系,它存在于@ 987654335@。如果您这样做@user.offers.first.purchases,您将(可能)看到以该用户作为卖家进行的购买。您可以在您的用户模型中添加has_many :as_seller_purchases, class_name: 'Purchase', through: :offers, source: :purchases 以快捷方式。
  • 我强烈建议您使用更好的名称重命名您的列,例如 Offer#user_id 可以变为 Offer#seller_idPurchase#buyer_id,它们都是用户记录的外键(您可以使用 ActiveRecord 进行配置,例如这个,例如在购买模型中:belongs_to :buyer_user, class_name: 'User', foreign_key: :buyer_id)

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


【解决方案1】:

首先,您要为 belongs_to 关联“别名”,以便清楚关联实际是什么:

class User
  has_many :offers, 
    dependent: :destroy,
    foreign_key: :seller_id # where to find user on the offers table
  has_many :purchases,
    dependent: :destroy,
    foreign_key: :buyer_id # where to find user on the purchases table
end

class Offer
  has_many :purchases
  # @todo write migration to change the column name from
  # user_id to seller_id
  belongs_to :seller, class_name: 'User'
end

class Purchase
  belongs_to :offer
  # @todo write migration to change the column name from
  # user_id to buyer_id
  belongs_to :buyer, class_name: 'User'
end

然后您就可以开始添加间接关联,而不会被您的智慧弄糊涂:

class User
  has_many :offers, 
    dependent: :destroy,
    foreign_key: :seller_id // where to find user on the offers table
  has_many :purchases,
    dependent: :destroy,
    foreign_key: :buyer_id // where to find user on the offers table
  has_many :sales,
    through: :offers,
    source: :purchases
end

class Offer
  has_many :purchases
  belongs_to :seller, class_name: 'User'
end

class Purchase
  belongs_to :offer
  belongs_to :buyer, class_name: 'User'
  has_one :seller, through: :offer # goes through the "offer" association above
end

这里的关键是:

has_many :sales,
  through: :offers,
  source: :purchases

这使您可以从用户遍历到用户是卖方的购买。

还有:

has_one :seller, through: :offer

这让您可以从购买到卖家。

# given @user
Purchase.where(seller: @user).where.not(rating: nil)
@user.sales.where.not(rating: nil)

【讨论】:

  • 非常感谢。我将在未来几天尝试此操作,并且(希望)将您的回复标记为已接受的答案。非常感谢。
  • 不应该将has_one :seller, through: :offer 改为has_one :seller, through: :offers 吗?
  • 否 - 您想通过 Purchase 上的 belongs_to :offer 关联(答案中省略了该关联),因此它必须是单数。当您使用 through: 选项时,它必须与您要加入的关联的名称相匹配 - 而不是表或类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-30
  • 1970-01-01
  • 1970-01-01
  • 2018-12-28
  • 2021-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多