http request (using net http or RestClient) inside my rails controller - ruby-on-rails

I have problem creating http request inside my controller action. I used net/http and RestClient but I can't get it to work on my local server url i.e http://localhost:3000/engine/do_process, I always get requesttimeout however It works with other valid url.
Hope you can enlighten me on this one. I did some research but I can't find resources as to why I got this timeout problem.
Sample controller code:
require 'rest_client'
class LgController < ApplicationController
def get_lgjson
response = RestClient.get("http://localhost:3000/engine/do_process_lg")
#generated_json = response.to_str
end
end

I encountered this problem today, too, exactly in the same context: using the Ruby RestClient to make a HTTP request inside a controller. It worked earlier in a different project using OpenURI without problems. This was surprising because both http libraries, the RestClient and OpenURI for Ruby, use the same library Net::HTTP.
It is the URL that makes the difference. We can make a connection to an external URL in the controller, but not to localhost. The problem seems to be the duplicated connection to localhost. There is already a connection to localhost open, and we are trying to open a second one. This does not seem to work in a single-threaded web server like Thin for instance. A multi-threaded web server such as Puma could help.

I think this is because you use single-threaded web server. You have two opportunities to fix.
use passenger
define if it makes sense to make net/http to localhost.

Related

Rails rewriting link from Blogger

I use rack-reverse-proxy to setup my Blogger.com to a subdomain of my Ruby on Rails app: pulpoludo.com/blog
It's work, but I have an issue with the link of Blogger which returns to blog.pulpoludo.com (where my Blogger blog is host).
I would like to rewrite this link. But I don't know-how. Can you help me?
(I have found someone who does this in PHP: https://matt-stannard.blogspot.com/2013/02/blogger-in-subdirectory-of-my-domain.html
But I would like to do the same thing with Rails and a gem maybe)
Indeed, you cannot use rack-reverse-proxy because it does not allow you to change the response (you need to rewrite the page you retrieve using a regular expression replacement, as in the example you link to.
Also, you should probably avoid using rack-reverse-proxy in production, as it will keep your ruby processes busy waiting for the backend responses, that might fail or be slow. And:
It is not meant for production systems
You should instead proxy from your front HTTP acceptor (nginx or other). For nginx you can see a very thorough response, using a combination of proxy_pass and sub_filter, at https://stackoverflow.com/a/32543398/384417.
edit: If it's not possible to use nginx or another reverse proxy, you can still do it in ruby.
rack-reverse-proxy supports transformers, you can build one yourself, and register it so it's run on the response. This (closed) issue will help, it is exactly what you need: https://github.com/waterlink/rack-reverse-proxy/issues/65. The caveat (as always when changing responses) is that you have to update the Content-Length response header to match the updated size of the body.

How to mock requests made by the browser in a Rails app?

WebMock works fine for requests made by the app. But how to mock AJAX requests made by the browser to 3rd party services?
Rails 4.
Finally found 2 answers:
Approach #1: Puffing Billy
A rewriting web proxy for testing interactions between your browser and external sites.
Works like WebMock:
proxy.stub('http://www.google.com/')
.and_return(:text => "I'm not Google!")
Approach #2: Rack Middleware
Although the previous approach can work, I discovered that it does not work with WebMock. So, if you want to mock your browser requests to external services, you can't mock your app requests.
The approach that worked for me is to run a separate Rack app and inject it into the middleware stack:
spec_helper.rb:
def test_app
Rack::Builder.new{
use ExternalServiceMock
run app
}.to_app
end
Capybara.app = test_app
ExternalServiceMock is a rack app that only responds to certain request paths.
For this particular app, all of the external service URI's were stored in configs, and I set them in the spec helper:
ENV[ 'EXTERNAL_SERVICE_URI' ] = 'http://localhost:3000'
This forces all external requests to be sent to the ExternalServiceMock.
So basically you only need to save the response from 3rd party services and stub the request, then you can test it! Also checkout VCR: https://github.com/vcr/vcr.

Heroku Rails app makes request to http endpoint instead of https

I have a Rails app that uses the gem Httparty. It makes a call to Stubhub's API with a base URI of https://api.stubhub.com. The app behaves as expected locally and makes successful calls. However, when deployed to Heroku I get 403 forbidden error -- it is making the request to http instead of https. Is Heroku forcing the GET request to an http endpoint? Why? How can I fix this?
Thanks!
I have been struggling with a similar issue for months now. It recently came to my attention that the SSL version could cause this timeout. Using HTTParty I resolved this like this:
HTTParty.get('url_here', ssl_version: :SSLv3).body
I am unsure as to which ssl_version token you will need, but in my case, this fixed the problem. Take a look here for a little more information about where this came from:
https://github.com/jnunemaker/httparty/issues/257
A warning: SSLv3 is not secure, but that does not stop people from continuing to use it.

Why can I not do a local Net::HTTP get request?

So I have a controller action that renders json.. I can visit the url in the browser and see the json data, verifying that the route is working properly...
Yet, if I do:
uri = URI("#{request.protocol}#{request.host_with_port}/my_controller/action")
Net::HTTP.get(uri)
I get "Timeout::Error: Timeout::Error"
... ?
You're using a single-threaded HTTP server, i.e. Webrick. This means that it will only be able to serve one request at a time. You're attempting to make a request to the webserver from within the webserver itself. It won't be able to complete this action because of now hopefully obvious reasons.
Use a different web server, such as Thin, that would allow for this, or choose a different way to do this.

How to support backwards compatibility with the changes to the Accept header handling in Rails 2.3.4

In Rails 2.3.4, the way Accept headers are handled has changed:
http://github.com/rails/rails/commit/1310231c15742bf7d99e2f143d88b383c32782d3
We won't Accept it
The way in which Rails handles incoming Accept headers has been updated. This was primarily due to the fact that web browsers do not always seem to know what they want ... let alone are able to consistently articulate it. So, Accept headers are now only used for XHR requests or single item headers - meaning they're not requesting everything. If that fails, we fall back to using the params[:format].
It's also worth noting that requests to an action in which you've only declared an XML template will no longer be automatically rendered for an HTML request (browser request). This had previously worked, not necessarily by design, but because most browsers send a catch-all Accept header ("/"). So, if you want to serve XML directly to a browser, be sure to provide the :xml format or explicitly specify the XML template (render "template.xml").
I have an active API which is being used by many clients who are all sending both a Content-Type and an Accept header, both set to application/xml. This works fine, but my testing under Rails 2.3.4 demonstrates that this no longer works -- I get a 403 Unauthorised response. Remove the Accept header and just sending Content-Type works, but this clearly isn't an acceptable solution since it will require that all my clients re-code their applications.
If I proceed to deploy to Rails 2.3.4 all the client applications which use the API will break. How can I modify my Rails app such that I can continue to serve existing API requests on Rails 2.3.4 without the clients having to change their code?
If I understand correctly the problem is in the Request headers. You can simply add a custom Rack middleware that corrects it.
Quick idea:
class AcceptCompatibility
def initialize(app)
#app = app
end
def call(env)
if env['Accept'] == "application/xml" && env['Content-Type'] == "application/xml"
# Probably an API call
env.delete('Accept')
end
#app.call(env)
end
end
And then in your environment.rb
require 'accept_compatibility'
config.middleware.use AcceptCompatibility
Embarrassingly enough, this actually turned out to be an Apache configuration issue. Once I resolved this, everything worked as expected. Sorry about that.
As coderjoe correctly pointed out, setting the Content-Type header isn't necessary at all -- only setting the Accept header.

Resources