【问题标题】:Rails - NoMethodErrorRails - NoMethodError
【发布时间】:2013-05-22 18:38:39
【问题描述】:

当我的 DeltaSynWorker 运行时,我收到 NoMethodErrors。这发生在作为当前工作应用程序的修订而构建的应用程序中。我不是最初的程序员,我是从 Java 背景开始的(我提到这一点是因为我可能遗漏了一些对其他人来说非常明显的东西)。当代码与当前在不同 Web 应用程序中正常工作的代码非常相似时,我无法弄清楚为什么会抛出 NoMethodeError

错误:

NoMethodError: undefined method `client' for #<ApiRequestBuilder:0x0000000705a8f0>

delta_sync_worker.rb

class DeltaSyncWorker < SyncWorker

  include Sidekiq::Worker
  sidekiq_options queue: "delta_syncs"

  def perform(subscriber_id, client_id)

      sleep(10)
      current_subscriber = ApiSubscriberDecorator.decorate(Subscriber.find(subscriber_id))
      Time.zone = current_subscriber.time_zone
      client = ApiClientDecorator.decorate(Client.find(client_id))
      arb = ApiRequestBuilder.new(URI.parse(SR_HOST + '/servlet/sync/process'))

      if arb.client(:subscriber => current_subscriber, :client => client)

        arb.transmit

        if arb.success?
          current_subscriber.touch(:sync_updated_at)
          decorated_client = ClientDecorator.decorate(client.model)        
          ConfirmationsSyncWorker.perform_in(1.hours, current_subscriber.id)
        else
          error_params = {:subscriber => current_subscriber.id, :response_body =>            arb.response.body, :request_body => arb.request.body, :sync_type => "DeltaSyncWorker"}
          Airbrake.notify(:error_class => "sync_error", :error_message => "Sync Error: #{arb.response.message}", :params => error_params)
        end
      end
    end
  end

api_request_builder.rb

require 'nokogiri'
class ApiRequestBuilder < AbstractController::Base
  include AbstractController::Rendering
  include AbstractController::Layouts
  include AbstractController::Helpers
  include AbstractController::Translation
  include AbstractController::AssetPaths

  self.view_paths = "app/api"

  attr_accessor :request_body, :request, :response, :append_request_headers, :request_method, :url

  def initialize(url, *args)
    @url = url
    if args
      args.each do |arg|
        arg.each_pair{ |k,v| instance_variable_set("@#{k.to_s}", v) }
      end
    end
  end

  # this will search for an api request template in api/requests, render that template and set any instance variables
  def method_missing(meth, *args, &block)

    if lookup_context.template_exists?("requests/#{meth.to_s}")

      if args
        args.each do |arg|
          arg.each_pair{|k,v| instance_variable_set("@#{k.to_s}", v) }
        end
      end

      @request_body = (render :template => "requests/#{meth.to_s}")
    else
      super
    end

  end

  def transmit
    @request_method ||= "Post"
    @request = "Net::HTTP::#{@request_method}".constantize.new(@url.path)
    @request['x-ss-user'] = @subscriber.sr_user if @subscriber &&        @subscriber.sr_user.present?
    @request['x-ss-pwd'] =  @subscriber.sr_password if @subscriber && @subscriber.sr_password.present?

    unless @append_request_headers.nil?
      @append_request_headers.each_pair{ |k,v| @request[k] = v }
    end
    @request.body = @request_body if request_body? && @request.request_body_permitted?

    @http = Net::HTTP.new(@url.host, @url.port)
    @http.use_ssl = true
    @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    @response = @http.request(@request)

  end

  def success?
    if @response.code == 200.to_s
      return true
    else
      return false
    end
  end

  def request_body?
    unless @request_body.nil?
      return true
    else
      return false
    end
  end
end

我一直在这里查看其他NoMethodError 问题,但我找不到适合我情况的答案。任何帮助是极大的赞赏。谢谢!

【问题讨论】:

    标签: ruby-on-rails nomethoderror sidekiq airbrake


    【解决方案1】:

    method_missing 将捕获未定义方法的已发送消息,最后对 super 的调用会将其传递给 Ruby 的标准 method_missing 行为,这就是您所看到的 (NoMethodError )。但是,只有在不满足 if 条件时才会发生这种情况,这就是我怀疑这里发生的情况,并且可以解释为什么它在某些情况下有效但在其他情况下无效。对 :client 的调用,在继承链中没有找到匹配的方法,将寻找一个名为“requests/client”的模板 - 尝试添加这个模板,看看是否能解决问题。

    【讨论】:

    • 好的,我在听你说的。 “api/requests/”路径中同时存在“_client.xml.api”模板和“client.xml.api”模板。也许模板本身有问题?
    • 可能是。我会尝试在method_missing 中添加一些puts 语句,以便您可以查看流控制 - 即if 语句中的puts "template exists"else 中的puts "template not found"
    • 啊,好的。好想法。我会试试的。谢谢!
    【解决方案2】:

    我知道我以前见过这个,我觉得它看起来不像,但基本上方法丢失只是拦截方法调用,当你调用 arb.client 时,它被方法丢失捕获,因此尝试呈现 api/client.xml.arb 或 api 无论文件类型是什么。 -- 请注意,在初始化程序目录中应该有一个名为 somethig 的文件,例如 api_template_handler.rb 或 arb_temmplate_handler.rb,它允许 rails 在视图目录中查看该模板类型 - 确保首先存在。另外旁注,_client.xml.api 是该目录中其他 api 请求使用的部分(完全同步),

    要调试 Id,请在以下行上方

    if lookup_context.template_exists?("requests/#{meth.to_s}")
    

    添加日志语句

    Rails.logger.debug "Can I see View?" + lookup_context.template_exists?("requests/#{meth.to_s}")
    

    如果为真,那么问题是由于缺少方法而没有正确捕获错误。如果为 false,则 sidekiq 工作人员未正确加载 rails,或者未将视图路径添加到 rails 视图路径。

    如果为真,我猜这可能与未加载客户端模型或客户端模型上的属性不存在有关,构建器试图调用,并且错误以某种方式冒泡到 api请求构建器类。

    哦,也只是一般的东西,但要确保 redis 和 sidekiq 正在运行,如果不是本地环境,请重新启动乘客。

    告诉我进展如何。

    【讨论】:

    • 尽管我添加了这一行(以及在不同位置放置了类似的日志语句),但我实际上并没有看到 production.log 中的输出。我确认 redis 和 sidekiq 正在运行,并通过以下方式重新启动了乘客:touch /webapps/rackapp/tmp/restart.txt 我可以看到 Sidekiq 中的工作人员尝试处理该作业,但随后失败并进入重试队列。
    • 对于它的价值,我还在生产服务器上的生产环境中的 Rails 控制台中尝试了以下操作:RAILS_ENV=production bundle exec rails console 然后include ActionView::LookupContext::ViewPaths 然后helper.lookup_context.template_exists?("requests/client.xml.api") 产生:=&gt; false
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 2013-05-15
    相关资源
    最近更新 更多