Ruby:如何将两个相似的方法合并为一个?

3

我在Rails应用程序的Ruby对象中有两个非常相似的方法。我知道它们可以合并,但我不知道如何做。 (如果您能找到处理可能为空值的更美观方式而不使用#try,将获得额外的分数。)

 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

尝试使用符号或其他方式来定义您的权限,而不是方法调用的行为。然后,您可以将其重构为一个单一的方法(is_admin_type),该方法接受资源和权限符号。 - user1898811
4个回答

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

如果有人输入了不存在的类型,会触发 NoMethodError。此外,如果添加更多的管理员类型,它也具备向前兼容性。

我会选择 def is_admin_of_type?,但除此之外,+1。 - Alex Wayne

2

与其使用collectinclude?机制,您可以简单地使用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
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

如果您没有进入if分支,则返回nil,因此像上面那样进行条件判断将产生与显式返回相同的结果,除非...

添加第二个参数并传递:staff或portal(或"staff"或"portal")。使用“send”将在运行时评估为“staff_admin?”或“portal_admin?”

使用detect而不是collect + include?将返回一个对象,如果至少找到一个对象,则!!双重否定将其转换为true / false结果。

在大局中,我个人会简单地这样做,因为resource.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 为空,那么你需要条件语句的第二部分,但是去掉 ".any?",否则你会在对 nil 进行 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?设置为私有。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接