activerecord - Rails ActiveSupport::Concern — scope can't call private class method - Stack Overflow

I'm trying to refactor a scope within a Concern so that the scope gets most of its logic by callin

I'm trying to refactor a scope within a Concern so that the scope gets most of its logic by calling different class methods, depending on an arg.

With "public" class methods, that works fine.

But I want those class methods to be private, so they are not mistaken for scopes and called by other developers. (because this will lead to unexpected results in the app.)

I tried a suggestion here and every other way I could find to declare these class methods private, but when I do that, they are inaccessible from within the scope.

module OrderingScopes
  extend ActiveSupport::Concern

  included do
    # This scope can handle methods like :method and :reverse_method
    scope :order_by, lambda { |method|
      method = method.dup.to_s
      reverse = method.sub!(/^reverse_/, "")
      scope = :"order_by_#{method}";
      # This check fails
      return all unless private_methods(false).include?(scope)

      scope = send(scope)
      scope = scope.reverse_order if reverse
      # Disambiguate grouped result order by adding an order by :id
      scope = scope.order(arel_table[:id].desc)
      scope
    }
 
    private_class_method :order_by_method_name
  end

  class_methods do
    def order_by_method_name
    end
  end
end

Also tried:

  class_methods do
    private

    def order_by_method_name
    end
  end

In both cases the scope fails:

> Model.order_by(:method_name)

  included do
    scope :order_by, lambda { |method|
      method = method.dup.to_s
      reverse = method.sub!(/^reverse_/, "")
      scope = :"order_by_#{method}";
      debugger

> private_methods(false).include?(:order_by_method_name)
false
> respond_to?(:order_by_method_name)
false

Is there a way to do this?

I'm trying to refactor a scope within a Concern so that the scope gets most of its logic by calling different class methods, depending on an arg.

With "public" class methods, that works fine.

But I want those class methods to be private, so they are not mistaken for scopes and called by other developers. (because this will lead to unexpected results in the app.)

I tried a suggestion here and every other way I could find to declare these class methods private, but when I do that, they are inaccessible from within the scope.

module OrderingScopes
  extend ActiveSupport::Concern

  included do
    # This scope can handle methods like :method and :reverse_method
    scope :order_by, lambda { |method|
      method = method.dup.to_s
      reverse = method.sub!(/^reverse_/, "")
      scope = :"order_by_#{method}";
      # This check fails
      return all unless private_methods(false).include?(scope)

      scope = send(scope)
      scope = scope.reverse_order if reverse
      # Disambiguate grouped result order by adding an order by :id
      scope = scope.order(arel_table[:id].desc)
      scope
    }
 
    private_class_method :order_by_method_name
  end

  class_methods do
    def order_by_method_name
    end
  end
end

Also tried:

  class_methods do
    private

    def order_by_method_name
    end
  end

In both cases the scope fails:

> Model.order_by(:method_name)

  included do
    scope :order_by, lambda { |method|
      method = method.dup.to_s
      reverse = method.sub!(/^reverse_/, "")
      scope = :"order_by_#{method}";
      debugger

> private_methods(false).include?(:order_by_method_name)
false
> respond_to?(:order_by_method_name)
false

Is there a way to do this?

Share Improve this question edited Mar 25 at 16:47 nimmolo asked Mar 25 at 7:26 nimmolonimmolo 5856 silver badges26 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

Rails automatically defines scope methods on a relation object and delegates to your model's class method, but only if method is public.

You can work around this by copying how rails defines the delegate method:

scope :order_by, lambda { |method|
  scoping { model.send(:"order_by_#{method}") }
}

https://api.rubyonrails./classes/ActiveRecord/Relation.html#method-i-scoping

Note, that within a scope you're working with an ActiveRecord::Relation object. You can use model attribute reader to get your model class. Since private class methods are not copied into the relation class you have to run your check on the model itself:

# private_methods(false).include?(scope)
model.private_methods(false).include?(scope)

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744212913a4563419.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信