在条件语句中使用检查方法的结果

时间:2018-12-01 16:41:33

标签: ruby ruby-on-rails-5

我正在尝试实现和Authorization模块,因为当前某种资源的授权逻辑在两个或三个不同的位置上分开了,即使我不确定这是否是最好的方法,至少我认为它将提供一些封装。

因为我要检查几种不同的东西

  1. 用户是否具有正确的角色
  2. 资源处于正确的状态以处理所需的操作
  3. 用户是否有权在此特定资源上执行所需的操作

因此,正如您所看到的,有几项检查,在这里我并不假装完全正确,但这与真实情况非常接近,因此我决定使用类似Result Object的方法。即使它实际上不是对象,而是struct,并且我没有使用Gem而是非常简单的自定义实现。

因此,我的Authorization模块的一部分是

module Authorization
  Result = Struct.new(:successfull?, :error)

  extend self

  def read(user, resource, message: 'Permission denied')
    can_read =
      [
        condition1,
        condition2,
        condition3
      ]

    return Result.new(can_read.any?, can_read.any? ? nil : message))
  end

但是,在这个Authorization模块中,我有很多方法,其中有些方法像这样在内部检查read

def assign(user, resource, message: 'Permission denied')
  return read(user, resource) unless read(user, resource).successfull?

  Result.new(true, nil)
end

所以我的主要问题是如何避免对read(user, resource)的两次调用。我猜一个选择就是在检查之前先调用它:

result = read(user, resource)
return result unless result.successfull?

但是我对Ruby还是陌生的,我怀疑也许还有更多类似红宝石的方法可以做到这一点。只是通过在条件检查中分配read的结果来以某种方式内联...但是,这只是一个疯狂的猜测。

还有另外一个问题,在我撰写本文时出现。目前,如果我想在授权通过时发送nil消息,我会这样做:

return Result.new(can_read.any?, can_read.any? ? nil : message))

因为message unless can_read.any?抛出错误,即使我认为它默认为nil。再说一遍,还有其他类似红宝石的方法吗?

1 个答案:

答案 0 :(得分:2)

第一部分可以用Object#yield_self书写:

def assign(user, resource, message: 'Permission denied')
  read(user, resource).yield_self do |res|
    res.successful? ? Result.new(true, nil) : res
  end
end

successfull?-> successful?出于英语原因。我不相信这比使用局部变量更具可读性。或者:

(res = read(user, resource)).successful? ? Result.new(true, nil) : res

关于第二个问题,您需要更多的括号

Result.new(can_read.any?, (message if can_read.none?))

不需要return

我还建议您放慢所有unless的速度,尝试尽可能将您的条件换成if-我发现让Result成为一个类非常有用并为其定义一个failed?方法。其实我会考虑的:

class Result
  def initialize(error)
    @error = error
  end

  def successful?
    @error.nil?
  end

  def failed?
    !successful?
  end
end

这取决于您的Result变得多么复杂,但是对于所示的用例,它会更干净一点。