Search code examples
ruby-on-railscontrollerrubygemssavon

NameError (uninitialized constant Savon::Request)


I'm trying to use this Ruby wrapper https://github.com/mattetti/Pvwatts but I have an issue with my controller app/controllers/projects_controller.rb (relevant excerpts)

require 'rubygems'
require 'savon'

class ProjectsController < ApplicationController
    <snip>
    def annual_production
        <snip>
        client = Savon::Client.new("http://pvwatts.nrel.gov/PVWATTS.asmx?WSDL")
        production_data = Pvwatts.new("<key>").yearly_production(:locationId => @locationId, :dc_rating => @dc_rating, :tilt => @tilt, :azimuth => @azimuth, :derate => @derate, :cost => @cost, :array_type => @array_type)
        <snip>
        respond_to do |format|
            if @project.update_attributes(params[:project])
                format.js
                format.html
            else
                format.html { render :action => "update" }
                format.json { render :json => @project.errors, :status => :unprocessable_entity }
            end
        end
    end
end

class Pvwatts
    Savon::Request.log = false
    <snip>
    def yearly_production(opts={})
        <snip>
        client = Savon::Client.new("http://pvwatts.nrel.gov/PVWATTS.asmx?WSDL")
        <snip>
        req = prep_request(@locationId, @dc_rating, @tilt, @azimuth, @derate, @array_type, @cost)
        response = client.get_pvwatts{|soap| soap.input = "GetPVWATTS"; soap.body = req }
        <snip>
    end
end

This is the definition of the button that triggers the SOAP request

<input type=button id='pvwatt_update_button_id' value="Update from PVWatts" class='pvwatt_update_button_class'>

When that button is clicked, I get this "500 Internal Server Error"

Started GET "/projects/annual_production?id=4&keys=8<key>&reference_state=California&reference_city=San+Francisco&locationId=23234&dc_rating=1&tilt=20&azimuth=180&derate=80&cost=0.1&array_type=0" for <server_ip_address> at Tue Nov 20 20:07:18 -0800 2012
Processing by ProjectsController#annual_production as */*
Parameters: {"array_type"=>"0", "azimuth"=>"180", "locationId"=>"23234", "dc_rating"=>"1", "reference_city"=>"San Francisco", "keys"=>"<key>", "id"=>"4", "derate"=>"80", "reference_state"=>"California", "cost"=>"0.1", "tilt"=>"20"}
Project Load (0.2ms)  SELECT "projects".* FROM "projects" WHERE "projects"."id" = ? LIMIT 1  [["id", "4"]]
Completed 500 Internal Server Error in 282ms

NameError (uninitialized constant Savon::Request):
app/controllers/projects_controller.rb:1697
app/controllers/projects_controller.rb:1628:in `annual_production'

Rendered /var/lib/gems/1.8/gems/actionpack-3.2.9/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.6ms)
Rendered /var/lib/gems/1.8/gems/actionpack-3.2.9/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.2ms)
Rendered /var/lib/gems/1.8/gems/actionpack-3.2.9/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (10.0ms)

Anyone knows what am I doing wrong?

Here is my installed gems list

root@sv-001:/home/user/myapp# gem list

*** LOCAL GEMS ***

actionmailer (3.2.9)
actionpack (3.2.9)
activemodel (3.2.9)
activerecord (3.2.9)
activeresource (3.2.9)
activesupport (3.2.9)
akami (1.2.0)
arel (3.0.2)
builder (3.0.4)
bundler (1.2.2, 1.2.1)
coffee-rails (3.2.2)
coffee-script (2.2.0)
coffee-script-source (1.4.0)
erubis (2.7.0)
execjs (1.4.0)
git (1.2.5)
gyoku (0.4.6)
hike (1.2.1)
httpi (1.1.1)
i18n (0.6.1)
jeweler (1.8.4)
journey (1.0.4)
jquery-rails (2.1.3)
json (1.7.5)
libv8 (3.3.10.4 x86-linux)
mail (2.4.4)
mime-types (1.19)
multi_json (1.3.7)
nokogiri (1.5.5)
nori (1.1.3)
polyglot (0.3.3)
rack (1.4.1)
rack-cache (1.2)
rack-ssl (1.3.2)
rack-test (0.6.2)
rails (3.2.9)
railties (3.2.9)
rake (10.0.2, 10.0.1)
rdoc (3.12)
sass (3.2.3)
sass-rails (3.2.5)
savon (1.2.0)
sprockets (2.2.1)
sqlite3 (1.3.6)
therubyracer (0.10.2)
thor (0.16.0)
tilt (1.3.3)
treetop (1.4.12)
tzinfo (0.3.35)
uglifier (1.3.0)
wasabi (2.5.1)

and here are my ruby and rails versions

root@sv-001:/home/user/myapp# gem -v
1.8.15
root@sv-001:/home/user/myapp# ruby -v
ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-linux]
root@sv-001:/home/user/myapp# rails -v
Rails 3.2.9
root@sv-001:/home/user/myapp# 

Update 1

NoMethodError (undefined method `debug' for :logger:Symbol):
app/controllers/projects_controller.rb:1757:in `yearly_production'
app/controllers/projects_controller.rb:1638:in `annual_production'

Update 2

NoMethodError (undefined method `get_pvwatts' for #<Savon::Client:0xb275c15c>):
app/controllers/projects_controller.rb:1737:in `yearly_production'
app/controllers/projects_controller.rb:1628:in `annual_production'

Update 3

The code that worked for me is the following:

Savon.configure do |c|
   c.log = false
   c.logger = Rails.logger
end

client = Savon::Client.new do
    wsdl.document = "http://pvwatts.nrel.gov/PVWATTS.asmx?WSDL"
end

response = client.request :wsdl, "get_pvwatts" do
  soap.body = req
end

rdata = response.to_hash

Solution

  • The syntax for Savon has changed since it crossed the 1.x version. You've got the latest version installed.

    I investigated the webservice in question using a tool called SoapUI. I highly recommend it while developing SOAP clients. You can create calls out of the tool and can tinker around on the SOAP level before you write your actual source code. For this giving (legacy?) webservice you need to set the SOAPAction explicitely.

    I put all of this in a working Ruby script. I didn't use the WSDL. Savon's WSDL support is not complete. The author is working on an improved version. I 'hardcoded' the namespace and the endpoint.

    #!ruby
    
    require 'savon'
    require 'pp'
    
    Savon.configure do |c|
      c.log = true
      c.pretty_print_xml = true
    end
    
    client = Savon::Client.new do
      # wsdl.document = "http://pvwatts.nrel.gov/PVWATTS.asmx?WSDL"
      wsdl.endpoint = "http://pvwatts.nrel.gov/PVWATTS.asmx"
      wsdl.namespace = "http://pvwatts.nrel.gov"
    end
    
    begin
      response  = client.request :pvw, "GetPVWATTS" do
        http.headers['SOAPAction'] = '"http://pvwatts.nrel.gov/GetPVWATTS"'
        soap.body = { 'pvw:key' => 'your_secret',
                      'pvw:latitude' => 43,
                      'pvw:longitude' => 280 }
      end
      pp response.to_hash
    rescue Savon::SOAP::Fault => error
      print error
    end
    

    It doesn't return a valid result on my machine because I'm lacking the authorization code. Let us know whether that helped you to make your next step.