在Rails中创建处理多个方法名称的单个方法?

时间:2015-08-03 08:29:39

标签: ruby-on-rails ruby ruby-on-rails-4

是否可以干掉以下代码:

def is_user?
  is_role? ROLES[:user]
end

def is_mod?
  is_role? ROLES[:mod]
end

def is_admin?
  is_role? ROLES[:admin]
end

private

def is_role?(role)
  self.roles & role == role
end

进入单个函数,但仍然能够将函数名称调用为当前函数(is_user?is_mod?等)

更新

使用Aetherus'回答下面我创建了以下用于管理用户角色(用户可以拥有多个角色):

class User < ActiveRecord::Base
  # Use bitwise values for more roles (double the previous values)
  ROLES = { user: 1, dummy: 2, mod: 4, admin: 8 } 

  # Add the desired role
  def add_role(role)
    self.roles |= ROLES[role]
  end
  # eg: add_role :admin

  # Removed the desired role
  def remove_role(role)
    self.roles &= ~ROLES[role]
  end

  # methods for each role (mod? admin? etc)
  ROLES.keys.each do |role|
    define_method("#{role}?") do
      self.roles & ROLES[role] == ROLES[role]
    end
  end
end

3 个答案:

答案 0 :(得分:4)

您可以使用一个ruby代码块定义多个方法。

%w(user mod admin).each do |role|
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
    def #{role}?
      role == '#{role}' && roles.include?('#{role}')
    end
  RUBY
end

或者更明确的方式:

%w(user mod admin).each do |role|
  define_method("#{role}?") do
    self.role == role && roles.include?(role)
  end
end

顺便说一句,在ruby中,不需要is_前缀,因为尾随?告诉程序员该方法返回truefalse。< / p>

答案 1 :(得分:2)

您可以使用method_missing

最简单的解决方案是:

class Roles
  def method_missing(method_name, *args, &block)
    if /^is_(?<role_name>\w+)\?$/ =~ method_name
      is_role?(role_name.to_sym)
    else
      super
    end
  end

  private

  def is_role?(role_name)
    # just for demo purposes
    p "Checking #{role_name}"
  end
end

roles = Roles.new

roles.is_user?
roles.is_mod?
roles.is_admin?

method_missing我正在尝试捕获任何未实现的方法(请注意,我删除了正确的方法is_user?is_mod?和{ {1}}),稍后,我正在检查方法的名称是否与正则表达式(is_admin?)的正确的格式,如果是,我正在重用捕获的{{ 1}}。

稍微限制/^is_(?<role_name>\w+)\?$/

这种方法的问题是,它会接受任何方法调用,比如说role_name。在某些情况下,这可能是可取的,有时则不是。如果您只想将其限制为您提到的3种类型的用户,可以将Regex更改为:

method_missing

最后一件事。在实施is_super_user?时,您还应该注意/^is_(user|mod|admin)\?$/ ,当您想要断言对象是否响应那些魔术方法时,这是非常关键的:

method_missing

有了这个,你就可以做到:

respond_to_missing?

了解更多here

希望有所帮助!

答案 2 :(得分:0)

@Jacob,如果您使用rails 4,则可以使用AR#enum功能(http://api.rubyonrails.org/classes/ActiveRecord/Enum.html),无需手动实现。