【发布时间】:2021-10-21 11:37:48
【问题描述】:
我正在尝试构建一个辅助方法,该方法将采用关键字 args 并基于某些逻辑对它们进行处理,这是一个示例:
def update_with_logic(widget:, user:)
# do some logic here
widget.user = user
end
现在这工作得很好,但是,我想支持 user 也被设置为用户的 ID。
但是,如果我们将 user: 3 发送到我们的 update_with_logic 方法中,我会收到以下错误:
ActiveRecord::AssociationTypeMismatch: User(#47287814961100) expected, got 3 which is an instance of Integer(#47287745166420)
如果您换一种方式尝试:widget.user_id = user 和 user 是 ActiveRecord::Model,它会将 user_id 设置为 nil(并且不会引发异常)
这让我很吃惊,因为我可以在 ActiveRecord::Query 设置中毫无问题地执行以下操作:
userModel = User.find 3
# Looking up by user_id while sending a user model as the value
Widget.where(user_id: userModel).to_sql
# => SELECT "widgets".* FROM "widgets" WHERE "widgets"."user_id" = 3
# Looking up by user association while sending a user_id (integer) as the value
Widget.where(user: 3).to_sql
# => SELECT "widgets".* FROM "widgets" WHERE "widgets"."user_id" = 3
我尝试过使用widget.attributes = { user: user },但是使用user = 3 时效果相同。 (引发 ActiveRecord::AssociationTypeMismatch)。
我找到的唯一解决方案是执行以下操作:
widget.user_id = user.is_a?(User) ? user.id : user
上面的解决方案有效,但是,它并不像一个干净的实现。我希望有人可以推荐一些更符合“The Rails Way®” ;)
【问题讨论】:
-
经过更多考虑,不确定您是否想要此功能。因为如果您支持通过
user_id保存user,您会鼓励开发人员发送不同的对象。假设您需要访问user.full_name,但是,user = 3,您必须进行大量检查才能看到user是什么类型的对象。这似乎会增加代码的复杂性(总体而言)。 -
尽管我不同意使用这种方法,但我确实想看看我是否可以建立一个支持所讨论的实现的关注点(包括@konstantin-strukov 建议以确保模型是预期的模型)签出:gist.github.com/anlek/9f888518d3273508caffafdb1afea07c
标签: ruby-on-rails ruby activerecord