2016-10-29 4 views
2

У нас есть два класса - User и GroupДинамическая делегация в Рубине

class User < ActiveRecord::Base 
    # Group Memberships 
    has_many :memberships, dependent: :destroy 
    has_many :groups, through: :memberships 
end 

class Group < ActiveRecord::Base 
    # Group has a property called 'name' 
    # Group members 
    has_many :memberships, dependent: :destroy 
    has_many :members, through: :memberships, source: :user 
end 

Это работает просто отлично, и мы можем создавать группы и добавлять пользователей к этим группам.

Какой самый чистый способ определить членство в группе пользователей? Что-то вроде: user.reviewer? где рецензент - это имя группы, без явного определения этих методов. Как это можно сделать с помощью делегирования?

У нас уже есть работа, хотя и уродливым способом. По достоинству оценят самое элегантное (и самое короткое) решение.

PS: Мы на Rails 4.2.7

+0

Для такой работы я предлагаю вам взглянуть на [Пандит] (HTTPS://github.com/elabs/pundit). У них уже есть эта функциональность, и они позволяют легко расширять ее с помощью собственного кода, не беспокоясь о DSL. Это хорошо работает с Devise, и это чистая радость для работы. – mutantkeyboard

ответ

1

Последний раз, когда я смотрел delegate не поддерживается для has_many отношений.

Самый простой способ - определить метод member_of?. Я делаю это здесь с помощью частного метода и использую memoized список имен групп.

class User < ActiveRecord::Base 
    # Group Memberships 
    has_many :memberships, dependent: :destroy 
    has_many :groups, through: :memberships 
    delegate :name to :groups 

    def member_of?(group_name) 
    group_names.include? group_name.to_s 
    end 

    private 

    def group_names 
    @group_names ||= groups.pluck(:name) 
    end 

end 

Используйте его как ...

my_user.member_of?(:reviewers) 

Если держать имена групп в единственном числе, вы все равно можете сделать более удобный для чтения вызова ... множественного числа

my_user.member_of?(:reviewers) 

И только ссылайтесь на аргумент как group_name.to_s.singularize в методе.

Обратите внимание, что вы можете поддержать my_user.reviewer?, добавив def method_missing вызов, но вы должны проверки, что этот метод является допустимым именем группы, а затем проверить, является ли пользователь членом группы, в противном случае поднять недостающий метод (т.е. super унаследованным method_missing). См. Здесь для простого объяснения того, как можно использовать method_missing. https://rosettacode.org/wiki/Respond_to_an_unknown_method_call#Ruby

+0

Спасибо Стив. Именно так мы это делаем в настоящее время. Удивление, если попытка и проверка может каким-то образом использоваться здесь. – nahankid

+0

Ну, это решение - это всего лишь два однострочных метода и примерно так же эффективно, как вы можете получить, поэтому я не уверен, что вы пытаетесь улучшить. Здесь вы можете пойти на чрезмерный рефакторинг. Если вы действительно хотите работать с 'my_user.reviewer? ', Тогда см. Мой другой ответ. – SteveTurczyn

0

это способ, которым Вы можете получить my_user.reviewer? работать ... добавить следующую строку в ваш класс User:

def method_missing(name, *args, &block) 
    if name.to_s.end_with?('?') 
    group_name = name.to_s.chomp('?') 
    if Group.find_by(name: group_name) 
     return groups.pluck(:name).include?(group_name) ? true : false 
    end 
    end 
    super 
end 
+0

Две проблемы с этим - 1) если группа не существует, она скрывает неправильный вызов метода и 2) она явно возвращает true/false в тройной форме. – nahankid

+0

Нет, если группа не существует, она попадает на 'super', поэтому унаследованный' method_missing' получает контроль. Он возвращает только «true» или «false», когда он знает, что существует группа (IE «' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' является именем группы – SteveTurczyn

+0

Был ли мой ответ прояснен? Здесь есть тест, чтобы убедиться, что мы смотрим на имя группы else, мы делаем стандартное 'method_missing'. Если это имя группы, только тогда мы возвращаем true или false в зависимости от того, принадлежим ли мы группе. – SteveTurczyn