Rails 有很多通过有一个多态
Posted
技术标签:
【中文标题】Rails 有很多通过有一个多态【英文标题】:Rails has many through has one polymorphic 【发布时间】:2022-01-17 12:39:39 【问题描述】:我正在尝试设置多态实体 has_one 位置,但一个位置可以属于许多多态实体。我遇到的困惑是我需要指定多态关联,而guess + check 不起作用,哈哈。
澄清一下,任何“可定位”都应该有一个位置,但一个位置应该能够有许多与之关联的可定位对象。
当前设置:
class User
has_one :locatable_location, as: :locatable
has_one :location, through: :locatable_locations
end
class Entity
has_one :locatable_location, as: :locatable
has_one :location, through: :locatable_locations
end
class LocatableLocation
belongs_to :locatable, polymorphic: true
belongs_to :location
end
class Location
has_many :locatable_locations
has_many :locatables, polymorphic: true, through: :locatable_locations
end
任何帮助都非常感谢:)
【问题讨论】:
【参考方案1】:因为我最终弄明白了,所以我会回答我自己的问题。
错误出现在位置模型中。改为
class Location
has_many :locatable_locations
has_many :users, through: :locatable_locations, source: :locatable, source_type: :User
has_many :entities, through: :locatable_locations, source: :locatable, source_type: :Entity
end
如果您想与“定位”建立关系,即获取所有关联的记录,您必须在 location 中定义一个方法,例如
def locatables
users + entities
end
如果你的用例有很多很多像我一样的定位,那么你也可以做类似的事情
class Location
RELATIONS = %i[User Entity]
has_many :locatable_locations
RELATIONS.each do |associated_klass|
has_many associated_klass.to_s.snake_case.to_sym, through: :locatable_locations, source: :locatable, source_type: associated_klass
end
def locatables
RELATIONS.reduce([]) |all, curr| all.append(send(curr.to_s.snake_case))
end
【讨论】:
【参考方案2】:我会考虑您是否只是不必要地过度复杂化。使用多态连接表的唯一实际优势是您可以使其他模型“可定位”,而无需向表中添加列。您实际上不能将它用作同质集合而不冒 N+1 个查询的风险,因为多态关联不支持预加载。
这种实现方式也不能保证用户只能拥有一个“当前位置”——由于简单的竞争条件,可能会出现重复。 has_one
关联实际上只是将 LIMIT 1
放在查询上。另一方面,belongs_to
只能有一个值。
最简单的解决方案是简单地将外键列添加到用户表和单独的关联:
module Locatable
extend ActiveSupport::Concern
included do
belongs_to :location
end
end
class User < ApplicationRecord
include Locatable
end
class Entity < ApplicationRecord
include Locatable
end
class Location < ApplicationRecord
has_many :users
has_many :entities
end
魔法总是有代价的——在这种情况下,它会彻底破坏您的数据库设计。
【讨论】:
以上是关于Rails 有很多通过有一个多态的主要内容,如果未能解决你的问题,请参考以下文章
Rails 4 ActiveRecord 有很多通过关系不能从 sql 文件读取