53
  1. User submits a form with some basic data.

  2. The data is received and treated by an action in the controller and more information that needs to remain private is added.

  3. Then I need to send a post request to an external website with all of the combined data from the controller.

What is the best way to do this?

Jonathan Soifer
  • 2,715
  • 6
  • 27
  • 50
Alex.Bullard
  • 5,533
  • 2
  • 25
  • 32

5 Answers5

88

The simpliest way is using ruby core library:

require "uri"
require "net/http"

params = {'box1' => 'Nothing is less important than which fork you use. Etiquette is the science of living. It embraces everything. It is ethics. It is honor. -Emily Post',
'button1' => 'Submit'
}
x = Net::HTTP.post_form(URI.parse('http://www.interlacken.com/webdbdev/ch05/formpost.asp'), params)
puts x.body

Pro Tip: Do an asynchronous request, using a gem like delayed_job or background_rb

ZazOufUmI
  • 3,212
  • 6
  • 37
  • 67
Vlad Zloteanu
  • 8,464
  • 3
  • 41
  • 58
  • 2
    An example on using delayed_job on Ryan's railscast: http://railscasts.com/episodes/171-delayed-job – Vlad Zloteanu Jul 28 '09 at 19:12
  • 3
    This was the first thing I attempted. Unfortunately it gives me an 'end of file reached' error. From searching around it seems that others have had similar problems. Anyone have any insights? – Alex.Bullard Jul 28 '09 at 19:41
  • To solve EOF error when using https, see http://stackoverflow.com/a/9227933/1161743 – Jonathan Lin Feb 05 '13 at 17:53
  • @VladZloteanu - why is your advice "do an asyncronius request, using a gem like delayed_job" ? thanks – dowi May 19 '16 at 09:03
34

Sorry, I neglected to mention that I was connecting to secure server. This seems to have been the reason that I was getting end of file errors. Adding using 'net/https' and calling use_ssl on connection solved the problem. Thanks for everyones help.

require 'net/https'
require 'open-uri'

url = URI.parse('https://MY_URL')
req = Net::HTTP::Post.new(url.path)
req.form_data = data
req.basic_auth url.user, url.password if url.user
con = Net::HTTP.new(url.host, url.port)
con.use_ssl = true
con.start {|http| http.request(req)}    

This is based off the source for the post_form method, so i guess I'll give vlad.zloteanu the answer.

Alex.Bullard
  • 5,533
  • 2
  • 25
  • 32
  • :) well.. 10qu, i'm glad it helped you. – Vlad Zloteanu Jul 29 '09 at 20:00
  • 2
    This seems to be working great, however I was expecting the controller to follow the redirection to the post as well, but it does not seems to be the case? Any any idea how I could do that? – Alex Sep 26 '11 at 07:14
  • 1
    Something I just worked out... setting the last line to response `res = con.start {|http| http.request(req)}` is useful. – Isaac Mar 11 '15 at 15:35
13

If the external server is RESTful, then simply create an ActiveResource model to handle your data.

Dave Powers
  • 2,051
  • 2
  • 30
  • 34
askegg
  • 664
  • 6
  • 11
5

I don't think redirect_to handles post requests because it uses http 302 (?) which just GETs the other page.

I believe you can do something like this

Class MyController < ActionController
    require 'net/http'

    def my_method
        #do something with the data/model

        my_connection = Net::HTTP.new('www.target.com', 80)
        reponse = my_connection.post(path_within_url, data)

        #do something with response if you want
    end

end

note: this is air coded and has not been tried or tested

ErsatzRyan
  • 3,033
  • 1
  • 26
  • 30
1

If you want to send JSON, all you need is something like the following (tested in Rails 6):

Net::HTTP.post(
  URI('https://example.com/some/path'),
  { "this is the": "request body" }.to_json,
  'Content-Type' => 'application/json'
)
soundly_typed
  • 39,257
  • 5
  • 28
  • 36