【问题标题】:Rails not recognizing inherited class methodRails 无法识别继承的类方法
【发布时间】:2015-04-16 16:25:36
【问题描述】:

我正在编写一个作为 API 的 Rails 应用程序。我正在绕过活动记录编写自己的超级类,该超级类负责进行 api 调用。 似乎 Rails 不喜欢父级中的某些方法名称并接受其他方法名称。当我打电话给ModelClass.parent_method 时,我得到一个NoMethodError (undefined method parent_method' for ModelClass:Class): 我的代码结构如下:

 #./lib/accounts_api
 module AccountsAPI
   class SomeOtherClass
     . . .
   end

   class AccountModel
     class << self

       #this method works without fail:
       def get id
        url = "path to fetch object"
        response = HTTParty.get(url)
        return self.new response.parsed_response
       end
       # this method cannot be found
       def update_existing options   
        url = "path to update object"
        response = HTTParty.put(url, :body => options)
        return self.new response.parsed_response
       end
    end
 end

然后,一个派生类:

class BankAccount < AccountsApi::AccountModel
  attr_accessor :id, :customer_id, :reference
  def initialize(options={})
    if options.respond_to? :each
      options.each do |key,val|
        target = "#{key}=".to_sym
        self.send(target, val) if self.respond_to?(target)
      end
    end
  end
end

还有我的控制器,错误的来源:

class BankAccountsController < ApplicationController
  #Works just fine without fail
  def show
    @bank_account = BankAccount.get params[:id]
    respond_to do |format|
      format.json { render :json => @bank_account, :status => :ok }
    end
  end
  #Throws:
  # NoMethodError (undefined method `update_existing' for BankAccount:Class):
  # app/controllers/bank_accounts_controller.rb:21:in update
  # without fail
  def update
    @bank_account = BankAccount.update_existing params[:bank_account]
    respond_to do |format|
      format.json { render :json => @bank_account, :status => :ok }
    end
  end
end

注意:为了清楚起见,我省略了方法中的一些内部结构(错误处理、验证、分配等)。

解决方法修复:

如果我将 update_existing 方法名称更改为更正式的名称,例如 put,它就可以正常工作。

还有什么奇怪的,就是没有 Stacktrace。我只是在日志中看到Rendered rescues layout 消息:

Rendered /home/eggmatters/.rvm/gems/ruby-2.1.1@my-gemset/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.6ms)
Rendered /home/eggmatters/.rvm/gems/ruby-2.1.1@my-gemset/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/_trace.erb (0.7ms)
Rendered /home/eggmatters/.rvm/gems/ruby-2.1.1@my-gemset/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (7.0ms)
Rendered /home/eggmatters/.rvm/gems/ruby-2.1.1@my-gemset/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (16.6ms)

更奇怪的是,从 irb 调用方法就可以了:

> options = {:id => "23", :customer_id => "123", :reference => "update"}
> BankAccount.update_existing options
=> (:bank_account => { {:id => "23", :customer_id => "123", :reference => "update"}, :id => "23"}

所以我猜,我在搞乱 Rails 消息传递。我还猜测我的 AccountModel 父类需要从 ActiveRecord 或其他 rails lib 继承一些东西,但是,这对于我来说太奇怪了,无法研究它。

注意:AccountsAPI 模块设置为包含在我的app/initializers 目录中。

另外,我忘了说,重启Passenger和/或Apache没有任何效果。

更新:进行临时修复/解决方法。将方法名称更改为put 仍然不起作用。如果我多次重新启动乘客,我可以让它更新,但它只会工作一次或两次,然后回到问题。

更新:我也不能在子模型上调用方法。在模型中,我添加了方法:

class BankAccount < AccountsApi::AccountModel
  . . .
  def self.update_wrapper options
    return self.update options
  end
  . . .
end

现在抛出:

NoMethodError (undefined method `update_wrapper' for BankAccount:Class):

【问题讨论】:

    标签: ruby-on-rails-4


    【解决方案1】:

    看起来在模块中包含父类以某种方式破坏了 rails 映射方法的方式。将其拉出(并重新启动Passenger)似乎可行:

    class BankAccount < AccountModel
      . . .
    end
    

    和父母:

    module AccountsAPI
      class SomeOtherClass
      . . .
      end
    end
    
    class AccountModel
      class << self
        def get id
        . . 
        end
    
       def update_existing options   
           . . .
       end
    end
    

    看起来它有效。不知道为什么。我以前见过:class Child &lt; Module::Parent 模式。正如我在帖子中所暗示的那样,我缺少一些 Railsy(可能是 ruby​​)配置方面的内容。

    我发现这是另一个模型(仅调用 get)实际上是“SomeOtherClass”的一个实例,因此它会暴露给模块内的类。我仍然愿意接受建议!

    【讨论】:

      【解决方案2】:

      看起来,Passenger 正在全局缓存模块,而不是在应用程序重新启动时更新它。将这两个类移动到 lib 文件夹中各自的脚本以及模块声明中完全有效:

      # ./lib/some_other_class.rb
      class SomeOtherClass
        . . .
      end
      
      # ./lib/account_model.rb
      class AccountModel
       . . .
      end
      

      Rails 显然将这些映射到应用程序级别的命名空间,因此声明如下:

      class MySomeOtherClassModel < SomeOtherClass
      

      class MyAccountModel < AccountModel
      

      被 Rails 发现为包含命名库,确保应用程序在加载时包含(即服务器启动)

      【讨论】:

        猜你喜欢
        • 2021-02-03
        • 2022-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多