Использовать результат проверенного метода внутри условного оператора - PullRequest
0 голосов
/ 01 декабря 2018

Я пытаюсь реализовать и 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 модуля IУ меня много методов, и некоторые из них проверяют 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 голосов
/ 01 декабря 2018

Первая часть может быть написана с помощью 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 es, попробуйте поменять ваши условия на if всякий раз, когда это возможно - я считаю весьма полезным сделать Result классом и определить для него failed? метод.На самом деле, я бы подумал:

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

  def successful?
    @error.nil?
  end

  def failed?
    !successful?
  end
end

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

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