2013-03-21 4 views
2

У меня есть два чрезвычайно аналогичные методы в моем Ruby-объекте для приложения Rails. Я знаю, что их можно комбинировать, я просто не знаю, как это сделать. (Дополнительные очки, если вы можете найти более красивый способ справиться с возможным Nils, кроме return unless, не используя #try.)Ruby: Объедините два подобных метода в один?

def is_portal_admin?(resource) 
    return unless resource.user && resource.user.clinic_memberships.any? 
    memberships = resource.user.clinic_memberships.collect { |membership| membership.portal_admin? } 
    memberships.include?(true) 
    end 

    def is_staff_admin?(resource) 
    return unless resource.user && resource.user.clinic_memberships.any? 
    memberships = resource.user.clinic_memberships.collect { |membership| membership.staff_admin? } 
    memberships.include?(true) 
    end 
+0

Попробуйте определить свои разрешения в терминах символа или чего-то еще, а не поведения вызова метода. Затем вы можете реорганизовать это на один метод (is_admin_type), который принимает ресурс и символ разрешений. –

ответ

3

Как насчет:

def is_admin_of_type?(type, resource) 
    return unless resource.user && resource.user.clinic_memberships.any? && type 
    memberships = resource.user.clinic_memberships.collect { |membership| membership.send("#{type}_admin?") } 
    memberships.include?(true) 
end 

Если кто-то дает несуществующий тип, it'l бросить NoMethodError. Кроме того, он совместим с переходом, если вы добавляете больше типов администраторов.

+0

Я бы пошел с 'def is_admin_of_type?', Но кроме этого, +1 –

+0

@AlexWayne: Спасибо. Я изменю это. – Linuxios

2

Вместо вашего механизма collect и include? вы можете просто использовать any?. Если clinic_memberships всегда возвращает массив (который он делает, если это, например, ассоциация has_many), вам даже не нужно это проверять.

def has_membership?(resource, &block) 
    return unless resource.user 
    resource.user.clinic_memberships.any?(&block) 
end 

Это тогда можно назвать как

has_membership?(resource, &:portal_admin?) 

что эквивалентно

has_memberhsip?(resource){|m| m.portal_admin?} 
+0

Элегантное решение – Intrepidd

0
def is_admin?(resource, kind) 
    if resource.user && resource.user.clinic_memberships.any? 
    !!resource.user.clinic_memberships.detect { |membership| membership.send("#{kind}_admin?") } 
    end 
end 

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

Добавьте второй параметр и пропуск: штат или: портал (или «персонал» или «портал»). Использование «send» будет eval во время выполнения в «staff_admin?» или "portal_admin?"

Использование обнаружения вместо сбора + включения? возвратит объект, если хотя бы один найденный и !! двойные отрицания, чтобы превратить его в истинный/ложный результат.

Я лично просто так делаю это с тех пор, как этот ресурс.user.clinic_memberships.any? спорен в великой схеме вещей:

def is_admin?(resource, kind) 
    !!resource.user.clinic_memberships.detect { |membership| membership.send("#{kind}_admin?") } if resource.user 
end 

Если вы на самом деле пытаетесь защититься от clinic_memberships быть нулевым, то вам нужна 2-й половины условного, но падение «? .any», в противном случае вы «Я получу ошибку при тестировании? против нуля.

0
def is_portal_admin?(resource) 
    is_admin_of_type?(resource, :portal) 
end 

def is_staff_admin?(resource) 
    is_admin_of_type?(resource, :staff) 
end 

def is_admin_of_type?(resource, type) 
    if (user = resource.user) 
    user.clinic_memberships.any? { |ms| ms.send("#{type}_admin?") } 
    end 
end 
  • Это избыточное, чтобы проверить, есть ли memberships.
  • Вы можете добавить || false после кондиционирования, чтобы убедиться, что ваш method? возвращает логическое значение.
  • Вы можете сделать is_admin_of_type? частным.
Смежные вопросы