напишите общий метод для этих 3 методов

#ruby-on-rails #ruby

#ruby-on-rails #ruby

Вопрос:

У меня есть модель пользователя, которая выглядит следующим образом

 class User

  ROLES = {
            "Admin" => 1,
            "Manager" => 2,
            "Officer" => 3
          }

  def admin?
    role == 1
  end

  def manager?
    role == 2
  end

  def officer?
    role == 3
  end

end
  

где role находится столбец в users таблице, и мне было интересно, могу ли я использовать общий метод для построения 3 методов проверки ролей из ROLES хэша?

Редактировать

итак, похоже, это ответ

 class User

  ROLES = {
            "Admin" => 1,
            "Manager" => 2,
            "Officer" => 3
          }

  # methods used to identify whether a user is a specific role
  ROLES.each { |k, v| define_method("#{k.downcase}?") { role == v } }

end
  

Комментарии:

1. ROLES не используется каким-либо полезным образом в вашем коде. Как вы хотите, чтобы это было задействовано?

2. роль def? current_user.role заканчивается?

3. @sawa .. ROLES в основном действует как виртуальная таблица roles . Я использую его в представлениях, чтобы найти роль по значению столбца role (1, 2 или 3), а также заполнить выпадающий список для роли в представлении добавления / редактирования. Здесь я хочу, чтобы он сопоставил имя метода со значением роли (1, 2, 3).

4. @mikhail.. Я использую эти методы, чтобы проверить, является ли пользователь администратором, менеджером или должностным лицом

5. @mikhail def role? current_user.role end нарушает соглашение ruby, возвращая число или строку вместо логического значения.

Ответ №1:

Я не полностью уверен в ваших намерениях, но, может быть, вот так?

 class User
  %w[admin manager officer].each_with_index{|m, i| define_method("#{m}?"){role == i 1}}
end
  

или, используя ROLES ,

 class User
  ROLES.each{|m, i| define_method("#{m.downcase}?"){role == i}}
end
  

Ответ №2:

Я думаю, есть пара вариантов.

Во-первых, вы могли бы добавить реализацию method_missing, чтобы проверить, является ли метод одним из имен вашей роли. Что-то вроде:

 def method_missing?(sym, *args)
  if args.empty? amp;amp; ROLES.any? { |r| r.downcase   "?" == sym.to_s }
    # No additional arguments and the symbol for the method called 
    # matches a role name
    role == ROLES[sym.to_s.chomp('?')] # Check the value
  else
    super
  end
end
  

В качестве альтернативы вы могли бы настроить методы из хэша ваших ролей:

 class User
  ROLES = { ... }
  ROLES.each_pair do |r, n|
    class_eval "def #{r.downcase}?; role == #{n}; end"
  end
end
  

Ответ №3:

Возможно, вы могли бы сделать это несколькими различными способами, вопрос в том, как вы хотите, чтобы это вело себя, и где вы хотите простоты использования / гибкости?

Если я пойму, что вы пытаетесь сделать, что-то вроде этого может помочь

 def to_methods(roles_hash)
  roles_hash.each_pair do |key, value|
    class_eval {
      "def #{key}?
         role == #{value}
       end" 
    }
  end
end
  

Это создаст для вас методы для каждой роли. Это то, что вы хотели сделать?

Комментарии:

1. это именно то, чего я хочу.. В принципе, я мог бы добавить больше ролей к хэшу ролей, и метод будет сгенерирован автоматически.

Ответ №4:

Я полагаю, вы могли бы сделать что-то подобное, но я думаю, что ваш способ читается лучше…

   (ROLES = {
    "Admin"   => 1,
    "Manager" => 2,
    "Officer" => 3,
  }).each { |k, v| define_method(k.downcase   '?') { role == v }}