将属性添加到ActiveRecord枚举字段

时间:2015-12-24 17:19:56

标签: ruby-on-rails activerecord

我的Rails 4应用中有User模型。它包含account_type

的枚举
class User < ActiveRecord::Base
  enum account_type: [manager: 0, contractor: 1, employee: 2]
end

目前account_type用于修改多个操作的行为。但在将来,我需要引入几个属性,这些属性对于不同的帐户类型会有不同的值(例如某些API端点的速率限制或订阅价格)。

我该如何处理?

我可以添加新模型UserAccountType模型,并在其与belongs_to模型之间设置has_many - User关联链接,但我将失去对{{1}等方法的访问权限由manager?方便地提供。此外,我将必须适当地播种相关表,这意味着我将不得不放置映射'帐户类型'&lt; - &gt; ActiveRecord中的整数,并确保它为所有帐户类型创建记录,这些帐户类型也不是DRY。有没有办法更好地做到这一点?

2 个答案:

答案 0 :(得分:3)

看起来你正在寻找一个简单的角色系统。 Rolify宝石非常适合:https://github.com/RolifyCommunity/rolify。除了包含的内容之外,还可以轻松添加其他便捷方法。

有足够的人试图解决这个问题,出现了一些模式。例如,您确定项目的生命周期中每个用户的单个角色是否足够?您可能需要数组类型(或一对多)而不是枚举。

如果您想自己实现它,如果您使用的是Postgres,则数组字段类型可能是存储和添加&#34;角色的好方法。至于方便的方法,你可以替换像is_manager这样的东西吗?几行。我不会让这阻止你创建一个更合适和可持续的数据模型。

示例:

def is_manager?
  User.find(1).roles.include?('manager')
end

答案 1 :(得分:1)

当您提到要为enum个对象添加额外属性时,您必须小心了解要添加的内容。

根据docs

  

声明一个枚举属性,其中值映射到数据库中的整数,但可以按名称查询。

基本上,这意味着enum属性的存储值将是一个数字; Rails会将这个数字“翻译”成冗长的形式。如果需要,可以使用单实例方法轻松实现。

因此,您提供给我们的用例无效:

  

请注意,使用数组时,从值到数据库整数的隐式映射是从值在数组中出现的顺序派生的。在示例中,:active映射为0,因为它是第一个元素,并且:archived映射到1.通常,第i个元素映射到数据库中的i-1。

     

Conversation.statuses[:active] # => 0

     

Conversation.statuses["archived"] # => 1

-

与您的问题的不同之处在于,如果您想将更多规范添加到enum功能,那么您真正进入了另一个模型的领域。

@errata所述,如果您想使用您的示例,您可以更好地使用基于角色的功能。

您从大型项目中学到的最好的事情之一是需要具体了解功能。很容易说“我需要一个新模型”,非常不同,以了解它在功能层面上必须做什么。

因此,我建议的是看看你想要实现的目标完全。如果你想要“额外”属性等,你需要另一个模型。如果您只是使用单个值,请坚持使用enum

  

某些API端点或订阅价格的费率限制

我个人会使用以下内容:

#app/models/user.rb
class User < ActiveRecord::Base
   belongs_to :account_type
   delegate :rate_limit, to: :account_type #-> @user.rate_limit.speed
end 

#app/models/account_type.rb
class AccountType < ActiveRecord::Base
   has_many :users
   belongs_to :rate_limit #-> maybe
end

这将允许您致电:

@user = User.find x
@user.rate_limit.throttle

可能会使用更灵活的东西,但上述情况应该没问题。