首页 > 解决方案 > Rails 5.2 多态关联与多态条件

问题描述

楷模:

class Car < ApplicationRecord
  belongs_to :user

  has_one  :listing, as: :listable
  has_one  :firm, as: :firmable
  has_one  :seller, as: :sellable
end

class Truck < ApplicationRecord
  belongs_to :user

  has_one  :listing, as: :listable
  has_one  :firm, as: :firmable
  has_one  :seller, as: :sellable
end

class Listing < ApplicationRecord
  belongs_to :listable, polymorphic: true
  has_many :favorites, dependent: :destroy
  has_many :users_who_favorited, through: :favorites, source: :user
end

并假设 Car 和 Truck 都有一个 user_id 字段......

Listing.includes(:listable)返回一个预先加载的列表 AR 关系。

但是,我需要按 user_id 过滤,所以我尝试了...

Listing.includes(:listable).where(user_id: 100)

但我得到一个错误..

ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column listings.user_id 不存在) LINE 1: SELECT "listings".* FROM "listings" WHERE "listings"."user_...

因为它似乎在列表中查找 user_id。但是,我需要在 listables 表上进行过滤,这意味着 Car 或 Truck 表。但是 listable 是定义的。

我也试过:

Listing.includes(listable:[:user]).where('users.id = 100')

但我得到...

ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR: missing FROM-clause entry for table "users") LINE 1: SELECT "listings".* FROM "listings" WHERE (users.id = 100) ... ^ : SELECT "listings".* FROM "listings" WHERE (users.id = 100) 限制 $1

更新:

然后试了

class Listing < ApplicationRecord
  belongs_to :listable, polymorphic: true
  has_many :favorites, dependent: :destroy
  has_many :users_who_favorited, through: :favorites, source: :user

  belongs_to :car, -> { includes(:listable).where(listable: { listable_type: Car.to_s }) }, foreign_key: :listable_id
  belongs_to :truck, -> { includes(:listable).where(listable: { listable_type: Truck.to_s }) }, foreign_key: :listable_id

end

并尝试Listing.includes(:car, :truck)但得到..

ActiveRecord::ConfigurationError(无法将“Car”加入名为“listable”的关联;也许您拼错了?)

因此,在上述工作正常之前,我无法尝试以下操作。

Listing.includes(:car, :truck).where(cars: { user_id: 1 }).or(Listing.includes(:car, :truck).where(trucks: { user_id: 1 }))

但是,我可以做 Listing.includes(:listable) 并且它确实有效,当我添加条件时它会中断。

标签: ruby-on-railsrubypolymorphismruby-on-rails-5.2

解决方案


这是一个非常有趣的问题,我问了几个月。然后我找到了解决方案。

在您的Listing模型中,为了能够包含您的polymorphic模型,您需要告诉您的模型它们是相关的。

class Car < ApplicationRecord
  belongs_to :user

  has_one  :listing, as: :listable
  has_one  :firm, as: :firmable
  has_one  :seller, as: :sellable
end

class Truck < ApplicationRecord
  belongs_to :user

  has_one  :listing, as: :listable
  has_one  :firm, as: :firmable
  has_one  :seller, as: :sellable
end

class Listing < ApplicationRecord
  belongs_to :listable, polymorphic: true
  has_many :favorites, dependent: :destroy
  has_many :users, through: :favorites

  #magic happens here
  belongs_to :car, -> { includes(:listable).where(listings: { listable_type: Car.to_s }) }, foreign_key: :listable_id
  belongs_to :truck, -> { includes(:listable).where(listings: { listable_type: Truck.to_s }) }, foreign_key: :listable_id

end

现在,你可以简单地做:Listing.includes(:car, :truck)它会完美地工作:-)

对于您的情况:

Listing.includes(:car, :truck).where(cars: { user_id: 1 }).or(Listing.includes(:car, :truck).where(trucks: { user_id: 1 }))

推荐阅读