处理不同类型用户的最佳方式?

时间:2009-10-15 01:20:40

标签: ruby-on-rails

我有一个大型Rails应用程序,通过单表继承有34种不同类型的用户。当应用程序最初设计时,假设用户将根据类型具有不同的行为。这个假设是错误的,所以我想重构。

问题是你如何重构用户STI?

  • 向用户添加大量布尔属性(即User#is_employee?User.is_contractor?
  • User#type重命名为User#user_type,然后根据字段
  • 进行字符串匹配
  • 一些可怕的查找表解决方案
  • 我想念的东西......

只是为了澄清,用户需要一个“类型”出于ACL的原因,但是对于STI来说,它们实际上只是空模型,而STI会导致问题,屁股中的一般痛苦等等。

3 个答案:

答案 0 :(得分:3)

听起来你真正需要的是角色而不是用户类型。我发现当你最终得到很多用户类型时通常会出现这种情况,因为有些用户有多个角色。

一个简单的ACL模型是:用户有很多角色,每个角色都有很多权限。 用户的权限集是用户所属的所有角色的所有权限集。

在更复杂的情况下,权限通常是计算属性而不是数据库中的行,原因很简单,权限有时是目标和基于时间(!)。

@user.can_view_payroll_info_for?(@employee, 2.years.ago) ==> true
@user.can_view_payroll_info_for?(@employee, Time.now) ==> false

大多数情况下,角色的分辨率与您需要的一样高:

@john.has_role(:content_author) ==> true
@john.has_role(:moderator) ==> true

@benny.has_role(:content_author) ==> true
@benny.has_role(:moderator) ==> false

@michael.has_role(:moderator) ==> true
@michael.has_role(:content_author) ==> false

如果您希望将角色规范化,则可以像为用户或连接表的逗号分隔(验证)字符串'角色'列一样简单地实现它。

答案 1 :(得分:0)

所有34个型号都是空的吗?

如果他们能做到:

self.inheritance_column = nil

在用户模型的顶部,您只需检查类型:

if @user.type == "Employee"
  # do something
end

答案 2 :(得分:0)

很难回答这个问题而不知道你的“ACL原因”将以何种方式使用该类型,但是......

根据我的经验,我总是和User#user_type一起去。总而言之,这些案件非常罕见,这很好。虽然我只有一些用户类型。另一个选项(可能是你用第二个选项提到的)是使用method_missing来处理字符串匹配,并允许它表现得像选项1。

例如:

def method_missing(method, *args, &block)
 if(method.to_s.starts_with?('is_'))
  self.user_type == method.to_s.gsub("is_", "").gsub("?", "")
 end
end

如果is_contractor?是承包商,则user_type会返回。

请注意,提供的代码段未经测试,并且链接的gsub看起来非常糟糕。我确信这可以写成一个很好的小正则表达式或其他一些聪明的方式。