首页 > 解决方案 > Rails API 类方法加载的奇怪行为

问题描述

项目设置:我正在运行与 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 以将其反转到以前的状态。当它再次发生时,我需要向后做同样的事情,令人作呕......

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

标签: rubyapiruby-on-rails-5mongoidclass-method

解决方案


我只会使用类实例变量:

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

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

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

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

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


推荐阅读