external HTTP requests

I've got a simple Rails 2.0 app with a (scaffold) resource (Provider) that has an integer (npi) and a string (name). I fleshed out the scaffold views a bit to display and give edit access to the int and string. The web interface works (out of the box, as expected).

Now I'm trying to use pure ruby to interface with this app. the following script executes successfully:

require 'net/http'

Net::HTTP.get_print(URI.parse('http://my.ip.add.ress:port/ providers.xml'))

The problem I'm having is posting data. I'm using this to test with, but I'm getting a 422 and an ActionController::InvalidAuthenticityToken exception:

require 'net/http'

Net::HTTP.get_print(URI.parse('http://my.ip.add.ress:port/providers'), {:npi => 12345, :name => 'Foobar'})

Is it looking for HTTP authentication?

Well, I just looked at the source of my new.html.erb in the browser and see the issue. There's a hidden field there named authenticity_token. I guess this is a security measure that prevents outside access from posting data.

No. If you create a form using form_tag etc.. there's a hidden field containing a token that is designed to mitigate crsf attacks. You can turn off forgery protection for indivdual actions by skipping the verify_authentication_token before_filter.


I added this line to the top of my controller

  protec_from_forgery :except => [:create]

and my ruby post script (in my first post) ran successfully. However the npi and name data did not propagate to the rails app (essentially it added a blank provider with only the id populated). I must not have the data packaged correctly in the post_form function

I peeked in my development.log when I attempt to create a Provider via my post_form function, and saw these parameters:

... Processing ProvidersController#create (.....   Session ID: .....   Parameters: {"action"=>"create", "controller"=>"providers", "npi"=>12345, "name"=>"Foobar" } ...

This didn't look right to me, so I created a Provider via the browser, and peeked in the log file:

... Processing ProvidersController#create (.....   Session ID: .....   Parameters: {"action"=>"create", "controller"=>"providers", "provider"=>{"npi"=>12345, "name"=>"Foobar"} ... } ...

AHA! I need to package my data into a subhash as the value of a 'provider' key. So I changed my post_form routine to:

Net::HTTP.get_print(URI.parse('http://my.ip.add.ress:port/providers'), {:provider => {:npi => 12345, :name => 'Foobar'}})

Running this generates a silent error (silent meaning only showing up in the log file). Here's what I got:

... Processing ProvidersController#create (.....   Session ID: .....   Parameters: {"action"=>"create", "controller"=>"providers", "provider"=>"npi12345nameFoobar" } ... NoMethodError (undefined method 'stringify_keys!' for "npi12345nameFoobar":String): ...

So now I'm stuck. Any ideas?

Bah cut'n'paste typos! In my first post (as well as my previous post), I pasted my get_print call, when I should have printed my post_form call. I have it right in my script, just not in this post.

Rails achieves the hash-like structuring through it's naming conventions. Try passing:

{ "provider[npi]"=>12345, "provider[name]"=>"Foobar"}

That did it! Looking at this I'm now kicking myself, since I should have realized this (having written gobs of tests using this same construct)

A similar syntax must be used when using the other form of posting

url = URI.parse('http://my.ip.add.ress:port') res = Net::HTTP.start(url.host, url.port) do |http|   # get a listing   http.get('/providers')   # post a new provider   http.post('/providers', 'provider[npi]=12345&provider[name]=Foobar')   # delete a provider   http.delete('/providers/3') end

This will come in very handy, as we have a backend service written in python. Now it can use pure http to communicate with our rails app