我正在尝试实现和Authorization
模块,因为当前某种资源的授权逻辑在两个或三个不同的位置上分开了,即使我不确定这是否是最好的方法,至少我认为它将提供一些封装。
因为我要检查几种不同的东西
因此,正如您所看到的,有几项检查,在这里我并不假装完全正确,但这与真实情况非常接近,因此我决定使用类似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
。再说一遍,还有其他类似红宝石的方法吗?
答案 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
变得多么复杂,但是对于所示的用例,它会更干净一点。