Rails - применить массив областей - PullRequest
0 голосов
/ 16 января 2019

У меня есть класс, который принимает массив областей и применяет их итеративно:

class AssignableLearningObjectives::Collector
  def initialize(user:, only_self_assignable: false, scopes: [])
    @user = user
    @only_self_assignable = only_self_assignable
    @scopes = scopes
  end

  .....

  def available_objectives
    objectives = assignable_objectives.or(manager_assigned_objectives).or(global_objectives).distinct
    return objectives unless scopes.any?

    scopes.each{ |scope| objectives = objectives.send(scope) }
    objectives
  end

Моя проблема с

scopes.each{ |scope| objectives = objectives.send(scope) }
objectives

Есть ли лучший способ сделать это? Я надеялся на метод rails apply_scopes или что-то подобное, однако не могу найти ничего подобного.

Меня беспокоит то, что области отправляются с контроллера, и пользователь может отправить запрос с областью «destroy_all» или с чем-то одинаково интересным.

Есть ли для меня простой способ позволить рельсам справиться с этим? Или мне нужно будет вручную проверить каждую область, прежде чем применить ее к коллекции?

Заранее спасибо

EDIT:

Я рад проверить каждую область в отдельности, если придется, но даже это вызывает проблемы. В рельсах есть метод, пропущенный в 3.0.9, который я мог бы использовать, Model.scopes:

https://apidock.com/rails/v3.0.9/ActiveRecord/NamedScope/ClassMethods/scopes

однако это устарело. Есть ли какой-нибудь метод, который я могу вызвать в классе, чтобы получить список его областей? Я не могу поверить, что эта функция была в рельсах 3 и полностью удалена ...

1 Ответ

0 голосов
/ 16 января 2019

Из справочника :

14 Области применения
[...]
Чтобы определить простую область действия, мы используем метод области действия внутри класса, передавая запрос, который мы хотели бы выполнить при вызове этой области:

class Article < ApplicationRecord
  scope :published, -> { where(published: true) }
end

Это то же самое, что и определение метода класса, и то, что вы используете, зависит от личных предпочтений:

class Article < ApplicationRecord
  def self.published
    where(published: true)
  end
end

Таким образом, scope - это в основном просто причудливый способ создания метода класса, который должен иметь определенное поведение (т.е. возвращать отношение), а любой метод метода класса, который возвращает отношение, является областью действия. scope раньше было чем-то особенным, но теперь это просто методы класса, и все методы класса копируются в отношения для поддержки цепочки.

Нет способа узнать, является ли метод Model.m "реальной" областью действия, которая будет возвращать отношение или какой-либо метод случайного класса, не выполняя его и не проверяя, что он возвращает, или вручную проверяя его исходный код. scopes метод, который вы ищете, ушел и никогда не вернется.

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

Единственный разумный вариант - вносить в белый список каждый классовый метод, который, как вы знаете, хорош и является тем, что вы хотите, чтобы пользователи могли вызывать. Затем вы должны отфильтровать массив scopes в контроллере и внутри AssignableLearningObjectives::Collector. Я бы проверил в обоих местах, потому что у вас могут быть разные критерии для того, что разрешено, в зависимости от того, какая информация доступна и по какому пути вы проходите через код; Скорее, СУХОЙ, но эффективность и надежность не дружат.

Вы можете применить белый список областей в конструкторе AssignableLearningObjectives::Collector или в available_objectives.


Если вы хотите что-то красивее, чем:

scopes.each{ |scope| objectives = objectives.send(scope) }
objectives

тогда вы можете использовать inject:

def available_objectives
  objectives = assignable_objectives....
  scopes.inject(objectives) { |objectives, scope| objectives.send(scope) }
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...