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.

On 7 Feb 2008, at 20:56, Reacher wrote:

{:npi => 12345, :name => ‘Foobar’})

Is it looking for HTTP authentication?

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.

Fred

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

On Feb 7, 3:06 pm, Frederick C. [email protected]

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

Congrats!