Rails 有很多通过有一个多态
Rails has many through has one polymorphic
我正在尝试设置一个多态实体 has_one 位置,但是一个位置可以属于多个多态实体。我 运行 的困惑是我需要指定多态关联,而 guess + check 不起作用,哈哈。
澄清一下,任何“locatable”都应该有一个位置,但一个位置应该能够有多个与之相关联的locatable。
当前设置:
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
非常感谢任何帮助:)
因为我最终弄清楚了,所以要回答我自己的问题。
错误出在位置模型中。改为
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
如果您想与“locatables”建立关系,即获取所有关联的记录,您必须在 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
我会考虑你是否只是不必要地使它过于复杂。使用多态连接 table 的唯一实际优势是您可以在不向 table 添加列的情况下创建额外的模型“locatable”。如果不冒 N+1 查询的风险,您实际上不能将它用作同质集合,因为多态关联不支持预先加载。
这种实现方式也不能保证用户只能拥有一个“当前位置”- 由于简单的竞争条件,可能会出现重复。 has_one
关联实际上只是将 LIMIT 1
放在查询上。 belongs_to
另一方面,只能有一个值。
最简单的解决方案是简单地向用户添加一个外键列 table 和一个单独的关联:
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
魔法总是有代价的——在这种情况下,它会完全破坏您的数据库设计。
我正在尝试设置一个多态实体 has_one 位置,但是一个位置可以属于多个多态实体。我 运行 的困惑是我需要指定多态关联,而 guess + check 不起作用,哈哈。
澄清一下,任何“locatable”都应该有一个位置,但一个位置应该能够有多个与之相关联的locatable。
当前设置:
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
非常感谢任何帮助:)
因为我最终弄清楚了,所以要回答我自己的问题。
错误出在位置模型中。改为
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
如果您想与“locatables”建立关系,即获取所有关联的记录,您必须在 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
我会考虑你是否只是不必要地使它过于复杂。使用多态连接 table 的唯一实际优势是您可以在不向 table 添加列的情况下创建额外的模型“locatable”。如果不冒 N+1 查询的风险,您实际上不能将它用作同质集合,因为多态关联不支持预先加载。
这种实现方式也不能保证用户只能拥有一个“当前位置”- 由于简单的竞争条件,可能会出现重复。 has_one
关联实际上只是将 LIMIT 1
放在查询上。 belongs_to
另一方面,只能有一个值。
最简单的解决方案是简单地向用户添加一个外键列 table 和一个单独的关联:
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
魔法总是有代价的——在这种情况下,它会完全破坏您的数据库设计。