Ruby on rails 在Rails中处理带有空对象的关联
我正在Rails应用程序中使用该模式来实现来宾用户帐户的概念 像许多应用程序一样,我在Ruby on rails 在Rails中处理带有空对象的关联,ruby-on-rails,rails-activerecord,null-object-pattern,Ruby On Rails,Rails Activerecord,Null Object Pattern,我正在Rails应用程序中使用该模式来实现来宾用户帐户的概念 像许多应用程序一样,我在ApplicationController上有一个名为current\u user的方法 对于未登录的用户,我希望使用来宾用户null对象 它在很多情况下都是有效的,但随后会出现如下情况- params.merge({ user: current_user }) MyModel.new(params) 当然,这失败了,但有以下例外 ActiveRecord::AssociationTypeMismatch:
ApplicationController
上有一个名为current\u user
的方法
对于未登录的用户,我希望使用来宾用户null对象
它在很多情况下都是有效的,但随后会出现如下情况-
params.merge({ user: current_user })
MyModel.new(params)
当然,这失败了,但有以下例外
ActiveRecord::AssociationTypeMismatch: User expected, got GuestUser
我的问题是,如何优雅地处理此类案件。空对象模式的思想是,您可以透明地交换这个空对象,并使它本质上是真实对象的duck类型
对于在对象上调用的方法,如何实现这一点是显而易见的,但在本例中,我希望能够传入它,并基本上让它将关联列设置为null
,而不需要一大堆自定义逻辑(无论如何,避免这就是null对象模式的全部要点)
多态关系并不完全是这样。如果您的MyModel接受用户id为null,那么您可以这样做
params.merge(user: current_user) unless current_user.is_a?(GuestUser)
MyModel.new(params)
快速回答:没有优雅的处理方式(我不确定优雅是如何量化的) 您必须创建一个关注点,模仿空对象所基于的模型(用户)的持久性方法。您还必须编写一些方法来安抚ActiveRecord,使相关列成为
nil
幸运的是,这个用例在这里使用空对象模式肯定不是一个好主意,因为如果您希望用户在“注册”之前具有任何类型的持久性,那么您需要数据库生成的ID来构建关联并维护引用完整性 允许在没有用户id的情况下创建一个
MyModel
,实际上会创建一个孤立的记录,只会给您在屏幕后面将其链接到用户的另一个问题。这就是为什么您的模式首先不应该允许它
相反,您希望在需要时创建来宾用户记录(如来宾用户将第一项添加到购物车时),并使用定期任务(如Cron选项卡)定期清除垃圾记录
我也会考虑如果你真的想把访客用户设置成一个单独的类,因为STI和多态在加入时会变得非常混乱。只需使用时间戳列(帐户激活时的记录)或枚举即可。一个选项是覆盖
用户=
方法,以便它知道GuestUser
的存在(并可以适当处理):
Rails中的所有质量分配方法(创建、更新等)都将使用适当的setter来设置值。如果这是应用程序中的常见模式,则很容易引起关注
如果在user\u id
列中不允许nil
,则您可以灵活地执行诸如分配哨兵值之类的操作,然后也可以在访问者中使用该值:
def user
if user_id == GUEST_USER_ID
GuestUser.new
else
super
end
end
我也有类似的问题。我刚从分配对象转到分配
object.id
,我在空对象上将其设置为nil。但我认为这是一种黑客行为。我不确定你在这里的意图。使用现有的开发良好的工具(如Desive和Rolify)可能会更好。我不认为这是一个很好的模式使用这里。我想说的是链接的答案是相当优雅:)
def user
if user_id == GUEST_USER_ID
GuestUser.new
else
super
end
end