【问题标题】:Rails API Strange behaviour on class method loadRails API 类方法加载的奇怪行为
【发布时间】:2020-10-12 10:12:52
【问题描述】:

项目设置: 我正在运行与 Mongoid 链接到 MongoDb 4.4.1 的 Rails 6.0.3.4 / Ruby 7.1.2 API,并获得了一个控制器,例如:

  module Api
    module V1
      class ApplicationController < ActionController::Base
        include Concerns::Api::Structuralizers::Collectionable
        include Concerns::Api::Structuralizers::Instanceable
        include Concerns::Api::Structuralizers::Showable
        include Concerns::Api::Structuralizers::Mutable
        include Concerns::Api::Structuralizers::Creatable
        include Concerns::Api::Structuralizers::Updatable
        include Concerns::Api::Structuralizers::Destroyable

        before_action :set_instance, only: %i[show edit update destroy]
        skip_before_action :verify_authenticity_token

        @@model_module = nil

        def initialize
          super
          @model_name = (@@model_module ? "#{@@model_module}::" : '') + controller_name.classify
          begin
            if @model_name && @model_name != 'Application'
              @model = @model_name.constantize
              @serializer = "#{@model_name}Serializer".constantize
            end
          rescue NameError => e
            Rails.logger.warn "TEST was unable to process model or serializer #{e}"
          end
          @acceptable_params = @regex_params = @regex_default_params = @regex_params = @valid_operators = []
        end
    
        class << self
          def model_module(model_module_name = nil)
            return @@model_module if !model_module_name

            @@model_module = model_module_name
          end
        end
      end
    end

那么这个继承行为的人:

module Api
  module V1
    class RunesController < ApplicationController
      model_module 'LanguageConcepts'
      include Concerns::Api::CommonControls
    end
  end
end

关注的是基本的 CRUD 集成。

我得到了这种非常奇怪和令人沮丧的行为:

启动时:

铁轨

当我在索引路径上调用 GET 方法时,我得到了这个:

Api::V1::RunesController:Class 的未定义方法 `model_module'

虽然使用控制台

轨道c

Api::V1::RunesController.model_module

我明白了:

“语言概念”

如果我更改方法类声明为:

def self.model_module[...]

然后保存,大多数时候问题会自行解决。 然后过了一会儿(我可以说是随机的时间),它又回到了被窃听的状态,我需要再次编辑 ApplicationController 以将其反转到以前的状态。 当它再次发生时,我需要向后做同样的事情,令人作呕......

我真的不明白发生了什么。任何人的想法?

【问题讨论】:

  • 我会考虑使用类实例变量而不是类变量。 @model_module = nil。它们没有线程安全性,并且类变量的重新加载问题不在类及其子类之间共享(这总是可取的)。
  • 该选项的问题是我无法在实例化之前设置它。有没有办法在第一次执行时以编程方式声明一个与所有实例共享的常量?
  • 那是不正确的。类实例变量是属于单例类的实例变量。 codegram.com/blog/…
  • 我建议用文字解释你想用model_module做什么。我的猜测是它所做的任何事情都没有正确考虑/集成 Rails 代码加载代码(ActiveSupport::Dependencies/zeitwerk 等)。

标签: ruby api ruby-on-rails-5 mongoid class-method


【解决方案1】:

我只会使用类实例变量:

module Api
  module V1
    class ApplicationController < ActionController::Base
      include Concerns::Api::Structuralizers::Collectionable
      include Concerns::Api::Structuralizers::Instanceable
      include Concerns::Api::Structuralizers::Showable
      include Concerns::Api::Structuralizers::Mutable
      include Concerns::Api::Structuralizers::Creatable
      include Concerns::Api::Structuralizers::Updatable
      include Concerns::Api::Structuralizers::Destroyable

      before_action :set_instance, only: %i[show edit update destroy]
      skip_before_action :verify_authenticity_token

      @model_module = nil

      def initialize
        super
        @model_name = (class.model_module ? "#{class.model_module}::" : '') + controller_name.classify
        begin
          if @model_name && @model_name != 'Application'
            @model = @model_name.constantize
            @serializer = "#{@model_name}Serializer".constantize
          end
        rescue NameError => e
          Rails.logger.warn "TEST was unable to process model or serializer #{e}"
        end
        @acceptable_params = @regex_params = @regex_default_params = @regex_params = @valid_operators = []
      end
  
      class << self
        attr_accessor :model_module
      end
    end
end

在类体中声明一个实例变量,就是在单例类的范围内声明它。结果就像一个类变量,但线程安全且不在类及其子类之间共享。在class &lt;&lt; self 中使用attr_accessor :model_module 声明了一个类级别的setter/getter。

不要使用“宏方法”,而是使用 setter/getter,因为它实际上并没有做任何了不起的事情:

module Api
  module V1
    class RunesController < ApplicationController
      self.model_module = 'LanguageConcepts'
      include Concerns::Api::CommonControls
    end
  end
end

此代码不需要读者查找model_module 的定义来查看发生了什么。我们可以立即看到我们正在分配一些东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多