Ruby on rails UUID和整数字段上的多态关联

Ruby on rails UUID和整数字段上的多态关联,ruby-on-rails,postgresql,Ruby On Rails,Postgresql,给定具有integer和uuid主键的表,集成多态联接(有许多)的最佳方法是什么?例如: class Interest < ActiveRecord::Base # id is an integer has_many :likes, as: :likeable end class Post < ActiveRecord::Base # id is a UUID has_many :likes, as: :likeable end class User < A

给定具有
integer
uuid
主键的表,集成多态联接(
有许多
)的最佳方法是什么?例如:

class Interest < ActiveRecord::Base
  # id is an integer
  has_many :likes, as: :likeable
end

class Post < ActiveRecord::Base
  # id is a UUID
  has_many :likes, as: :likeable
end

class User < ActiveRecord::Base
  has_many :likes
  has_many :posts, through: :likes, source: :likeable, source_type: "Post"
  has_many :interests, through: :likes, source: :likeable, source_type: "Interest"
end

class Like < ActiveRecord::Base
  # likeable_id and likeable_type are strings
  belongs_to :likeable, polymorphic: true
  belongs_to :user
end
然而:

user.interests
给出:

PG::UndefinedFunction:错误:运算符不存在:整数=字符变化 第1行:…在“兴趣”上的“兴趣”内部连接“喜欢”。“id”=“喜欢”。。。。 ^ 提示:没有与给定名称和参数类型匹配的运算符。您可能需要添加显式类型转换。 :从“兴趣”中选择“兴趣”。*在“兴趣”中加入“喜欢”。“id”=“喜欢”。“可爱的id”在“喜欢”的位置。“用户id”=“1”和“喜欢”。“可爱的类型”=“2”


确保正确施法的最佳方法是什么?

我不擅长使用ActiveRecord,这肯定不是您想要的答案,但如果您需要临时解决方案,直到找到解决方案,您可以覆盖getter:

class User
  def interests
    self.likes.select{|like| like.likeable._type == 'Interest'}.map(&:likeable)
  end
end
*非常难看,因为它会加载所有用户喜欢的内容,然后对它们进行排序

编辑我发现:

self.likes.injection([])do | result,like|

结果您能描述一下您的
likes
表吗?我想它包含

  • user\u id
    作为整数
  • likable_id
    作为整数
  • likable_type
    作为整数
  • 任何第三方字段
因此,从技术上讲,您不能将
uuid
字符串和
id
作为两个字段
likable_id
likable_type
范围内的整数创建相同的多态关联


作为解决方案-您可以简单地添加
id
作为
posts
表的主键,而不是
uuid
。如果您可能不想在URL中显示post的id,或者出于其他安全原因,您仍然可以像以前一样使用
uuid

您可以定义自己的方法来检索
likes
在您感兴趣的
模型中

def likes
  Like.where("likeable_type = ? AND likeable_id = ?::text", self.class.name, id)
end

这个解决方案的问题是,您没有定义关联,因此像“has\u many to”这样的东西不起作用,您还必须自己定义这些方法/查询。

您是否考虑过在关联宏中键入外键或主键之类的事情?例如,
has\u many:likes,foreign_key:“id::UUID”
或类似内容。

无法使用Rails指定必要的强制转换。相反,使用强制转换添加生成的列,并声明一个额外的属于关联以使用它。例如,在迁移中:

add_column :interests, :_id_s, 'TEXT GENERATED ALWAYS AS (id::text) STORED'
add_index :interests, :_id_s
在您的模型中:

class Like
  belongs_to :_likeable_cast, polymorphic: true, primary_key: :_id_s, foreign_key: :likeable_id, foreign_type: :likeable_type

class User
  has_many :interests, through: :likes, source: :_likeable_cast, source_type: "Interest"
然后,
user.interests
通过替代关联加入,即使用生成的列和强制转换


我建议对likeable_id列使用一种列类型的文本而不是varchar,以避免在连接过程中进行不必要的转换,并确保使用索引。

这是一个老问题,但我的建议如下

这更像是一个架构问题。不要将UUID ID和整数ID组合在一起,这会很快变得混乱。如果可以,请将整数ID迁移到UUID或将UUID还原为整数ID

我的经验是,最好的解决方案可能是使用相当友好的ID gem:

在关闭的情况下,这将在将来被打破,它基本上只是一个slug生成/管理工具,slug将使用这种路由路径:
posts/this-is-a-potential-slug
,而不是
posts/1
,但是没有任何东西阻止您使用
posts/
posts/


通常,如果您使用UUID,这是因为您不想显示顺序整数。友好的ID可以很好地避免该问题。

这会返回错误对象的数组(
,而不是
兴趣
),修复使用映射会出现
N+1
问题。请显示模式
add_column :interests, :_id_s, 'TEXT GENERATED ALWAYS AS (id::text) STORED'
add_index :interests, :_id_s
class Like
  belongs_to :_likeable_cast, polymorphic: true, primary_key: :_id_s, foreign_key: :likeable_id, foreign_type: :likeable_type

class User
  has_many :interests, through: :likes, source: :_likeable_cast, source_type: "Interest"