代码之家  ›  专栏  ›  技术社区  ›  Mark

Rails-应用范围数组

  •  1
  • Mark  · 技术社区  · 6 年前

    我有一个类,它接受一个范围数组并迭代地应用它们:

    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方法应用范围或类似的东西,但是找不到类似的东西。

    我担心的是范围是从控制器发送的,用户可以提交一个范围为“全部销毁”或其他同样有趣的请求。

    有什么简单的方法让Rails来处理这个问题吗?或者,在将每个作用域应用到集合之前,需要手动检查它吗?

    提前谢谢

    编辑:

    如果必须的话,我很乐意单独验证每个作用域,但即使这样也会引起问题。Rails中有一个方法在3.0.9中被丢弃,我可以使用它,model.scopes:

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

    不过,这已被否决。有没有方法可以调用类来列出它的作用域?我不敢相信这个功能在Rails 3中被完全删除了…

    1 回复  |  直到 6 年前
        1
  •  1
  •   mu is too short    6 年前

    fine guide :

    14个作用域
    […]
    为了定义一个简单的范围,我们在类内使用scope方法,传递调用这个范围时要运行的查询:

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

    这与定义类方法完全相同,您使用的是个人偏好问题:

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

    所以 scope 主要是创建一个类方法的一种奇特的方法,该方法应该具有特定的行为(即返回一个关系),任何返回一个关系的类方法方法都是一个范围。 范围 以前是很特别的,但现在它们只是类方法,所有类方法都复制到关系以支持链接。

    没有办法知道如果方法 Model.m 是一个“实际”范围,它将返回一个关系或某个随机类方法,而不运行它,也不检查它返回的内容或手动检查它的源代码。这个 scopes 你寻找的方法已经不复存在,永远不会回来。

    你可以试着黑名单的每一个类方法,你知道是坏的;这种方式谎言和疯狂。

    唯一明智的选择是白名单每一个你知道是好的类方法,是你希望用户能够调用的东西。那么你应该过滤 作用域 在控制器和内部排列 AssignableLearningObjectives::Collector . 我会检查这两个地方,因为根据可用的信息和代码使用的路径,对于允许的内容,您可能有不同的标准;我想稍微少一点干巴巴的,但是效率和健壮性不是朋友。

    您可以在 可分配的LearningObjectives::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