Rails: Как переопределить или сделать приватным данную область из включенного Концерна? - PullRequest
0 голосов
/ 23 мая 2019

У меня есть проблема, которая добавляет scope к ActiveRecord классам, которые его включают.В большинстве случаев все нормально, но в зависимости от класса могут быть дополнительные критерии, которым необходимо соответствовать.Я не хочу переписывать область действия в модели, но могу просто добавить метод дополнительных критериев.

Вот что я пытаюсь сделать:

module MyConcern
  extend ActiveSupport::Concern

  included do
    # I've included the fact I pass a limit variable here because my scope also does this, in case that's relevant for solving this.
    # I'd like this to be private or not accessible via `MyModel._my_scope`
    scope :_my_scope, ->(limit = nil) { (joins, wheres, order etc etc).limit(limit) }
    scope :my_scope, ->(limit = nil) { _my_scope(limit) }
  end
end

class MyModel < ApplicationRecord
  include MyConcern

  # Including the "private" scope to add my extra criteria.
  scope :my_scope, ->(limit = nil) { _my_scope(limit).where(foo: 'bar') }
end

class AnotherModel < ApplicationRecord
  include MyConcern

  # I like the default behavior here so nothing else to do
end

Это работает, но вне класса вы можете сделать это: MyModel._my_scope что, я думаю, нормально - может быть, есть время, когда я хочу поведение по умолчанию - но в этом случае я не думаю, что у меня есть, и я чувствую, что инкапсулирую _my_scope это путь.

Я предполагаю, что возможно создать метод частного класса в MyConcern, который будет включен в MyModel, но это, похоже, не работает, и я не совсемConcern / mixin master пока не знаю, как это сделать.Кроме того, Concerns считаются миксинами?Есть ли разница?Это было бы полезно знать также.

1 Ответ

1 голос
/ 24 мая 2019

Вы можете достичь той же функциональности областей с помощью методов класса, которые вы можете наследовать и расширять для этого случая.Это не сильно отличается от вашей реализации;просто избегает использования дополнительного _ метода, используя метод класса вместо области видимости.Например,

module MyConcern
  extend ActiveSupport::Concern

  class_methods do
    def my_scope(limit = nil)
      (joins, wheres, order etc etc).limit(limit)
    end
  end
end

class MyModel < ApplicationRecord
  include MyConcern

  def self.my_scope(limit = nil)
    super.where(foo: 'bar')
  end
end

class AnotherModel < ApplicationRecord
  include MyConcern
end

Для второй части вашего вопроса: технически проблема - рубиновый миксин;это просто соглашение, чтобы организовать / сгруппировать миксины, которые включены в ваши модели только как проблемы.Использование ActiveSupport :: Concern позволяет вам добавить дополнительные функциональные возможности, связанные с моделью, в ваши миксины, такие как область действия, проверки и т. Д., Которые вы не можете получить с помощью обычного модуля.Например, вы не можете сделать

module MyConcern
  scope :my_scope, ->(limit = nil) { _my_scope(limit) }
end

class MyModel < ApplicationRecord
  include MyConcern # this will raise an error
end
...