Get redirect of a URL in Ruby - ruby-on-rails

According to Facebook graph API we can request a user profile picture with this (example):
https://graph.facebook.com/1489686594/picture
But the real image URL of the previous link is:
http://profile.ak.fbcdn.net/hprofile-ak-snc4/hs356.snc4/41721_1489686594_527_q.jpg
If you type the first link on your browser, it will redirect you to the second link.
Is there any way to get the full URL (second link) with Ruby/Rails, by only knowing the first URL?
(This is a repeat of this question, but for Ruby)

This was already answered correctly, but there's a much simpler way:
res = Net::HTTP.get_response(URI('https://graph.facebook.com/1489686594/picture'))
res['location']

You can use Net::Http and read the Location: header from the response
require 'net/http'
require 'uri'
url = URI.parse('http://www.example.com/index.html')
res = Net::HTTP.start(url.host, url.port) {|http|
http.get('/index.html')
}
res['location']

You've got HTTPS URLs there, so you will handle that...
require 'net/http'
require 'net/https' if RUBY_VERSION < '1.9'
require 'uri'
u = URI.parse('https://graph.facebook.com/1489686594/picture')
h = Net::HTTP.new u.host, u.port
h.use_ssl = u.scheme == 'https'
head = h.start do |ua|
ua.head u.path
end
puts head['location']

I know this is an old question, but I'll add this answer for posterity:
Most of the solutions I've seen only follow a single redirect. In my case, I had to follow multiple redirects to get the actual final destination URL. I used Curl (via the Curb gem) like so:
result = Curl::Easy.perform(url) do |curl|
curl.head = true
curl.follow_location = true
end
result.last_effective_url

You can check the response status code and get the final URL recursively using something like get_final_redirect_url method:
require 'net/http'
def get_final_redirect_url(url, limit = 10)
uri = URI.parse(url)
response = ::Net::HTTP.get_response(uri)
if response.class == Net::HTTPOK
return uri
else
redirect_location = response['location']
location_uri = URI.parse(redirect_location)
if location_uri.host.nil?
redirect_location = uri.scheme + '://' + uri.host + redirect_location
end
warn "redirected to #{redirect_location}"
get_final_redirect_url(redirect_location, limit - 1)
end
end
I was facing the same issue. I solved it and built a gem final_redirect_url around it, so that everyone can benefit from it.
You can find the details on uses here.

Yeah, "Location" response header tell you the actual image URL.
However, if you use the picture as the user's profile image on your site, I recommend you to use "https://graph.facebook.com/:user_id/picture" style URL instead of actual image URL.
Otherwise, your users will see lots of "not found" images, or outdated profile images in the future.
You just put "https://graph.facebook.com/:user_id/picture" as the "src" attribute of "img" tag.
They browser gets the updated image of the user.
ps.
I have such troubles on my site with Twitter & Yahoo! OpenID now..

If you want a solution that:
does not use gems
follows all redirects
works also with url-shortening services
require 'net/http'
require 'uri'
def follow_redirections(url)
response = Net::HTTP.get_response(URI(url))
until response['location'].nil?
response = Net::HTTP.get_response(URI(response['location']))
end
response.uri.to_s
end
# EXAMPLE USAGE
follow_redirections("https://graph.facebook.com/1489686594/picture")
# => https://static.xx.fbcdn.net/rsrc.php/v3/yo/r/UlIqmHJn-SK.gif

Related

Instagram embed code from url (Rails)

In my application, I would like to allow user introduce a url of instagram, and then automatically retrieve the embed code of it.
I found this reference:
https://www.instagram.com/developer/embedding/#oembed
When I try the given example (https://api.instagram.com/oembed?url=http://instagr.am/p/fA9uwTtkSN) in my Chrome browser, I get the json with the code I am looking for.
However, if I try this from the rails console:
Net::HTTP.get_response(URI("https://api.instagram.com/oembed?url=http://instagr.am/p/fA9uwTtkSN"))
I get this:
#<Net::HTTPMovedPermanently 301 MOVED PERMANENTLY readbody=true>
I saw that instagram have a new API, but I don't want to make user authenticate from instagram.
Is there a way to do it?
You can use oembed gem by soulim. nice and clean way to get embed code
In case of instagram it goes like
include following line in your gem file
gem 'oembed'
next
bundle install
create a helper class
class InstaApi
include Oembed::Client
def endpoint_uri
'http://api.instagram.com/oembed'
end
end
Now you can use
instClient = InstaApi.new
info = instClient.fetch('http://instagr.am/p/BUG/')
to Get your embed code
embed_code = info["html"]
Using the docs
def fetch(uri_str, limit = 10)
# You should choose a better exception.
raise ArgumentError, 'too many HTTP redirects' if limit == 0
response = Net::HTTP.get_response(URI(uri_str))
case response
when Net::HTTPSuccess then
response
when Net::HTTPRedirection then
location = response['location']
warn "redirected to #{location}"
fetch(location, limit - 1)
else
response.value
end
end
str = "https://api.instagram.com/oembed?url=http://instagr.am/p/fA9uwTtkSN"
response = fetch(str)
redirected to https://api.instagram.com/publicapi/oembed/?url=http://instagr.am/p/fA9uwTtkSN
redirected to https://www.instagram.com/publicapi/oembed/?url=http://instagr.am/p/fA9uwTtkSN
redirected to https://api.instagram.com/oembed/?url=http://instagr.am/p/fA9uwTtkSN
=> #<Net::HTTPOK 200 OK readbody=true>
response.body
=> # JSON response
So just follow the redirects.

Ruby on rails HTTP request issue

I am an newbie to Ruby on Rails. I have a url which points to a JSON output. When I ran the URL directly like http://user:pass#myurl.com/json, I am getting the response without any authendication. However http://myurl.com/json requires a username and password through a standard apache pop up authentication box. I have tried to access this URL from my rails controller like the following:
result = JSON.parse(open("http://user:pass#myurl.com/json").read)
When I try to do, I just get an error which says ArgumentError, userinfo not supported. [RFC3986]
Also I have tried the below one. I am getting a 401-Unauthorized error
open("http://...", :http_basic_authentication=>[user, password])
How can I make a request that works in this case. Any help would be appreciated.
You need to use Net::HTTP (or some other HTTP client).
require 'net/http'
require 'uri'
require 'json'
uri = URI('http://myurl.com/json')
req = Net::HTTP::Get.new( uri )
req.basic_auth 'user', 'pass'
res = Net::HTTP.start(uri.hostname, uri.port) {|http|
http.request(req)
}
result = JSON.parse(res.body)
puts result

How do I check if a file exists using its URL without downloading it?

I need to write code which will determine if a file exists by checking its URL.
Currently I implement this:
error_code = 400;
response = Net::HTTP.get_response(URI(url));
return response.code.to_i < error_code;
But, it's not working right because each time it downloads the file, which is really slow if I have big files or a lot of them.
How do I determine if a file exists on the remote side without downloading it?
If you want to use Rubys included Net::HTTP then you can do it this way:
uri = URI(url)
request = Net::HTTP.new uri.host
response= request.request_head uri.path
return response.code.to_i == 200
With the rest-client gem installed, do something like this
require "rest-client"
begin
exists = RestClient.head("http://google.com").code == 200
rescue RestClient::Exception => error
exists = (error.http_code != 404)
end
Then "exists" is a boolean depending whether if it exists or not. This will only get the header information, not the file, so it should be the same for small or big files.
I'd write it this way:
require 'net/http'
ERROR_CODE = 400
response = Net::HTTP.start('www.example.net', 80) do |http|
http.request_head('/index.html')
end
puts response.code.to_i < ERROR_CODE
Which outputs true because I got a 302 for the response.code.

The most super simple example to start woking with NetHTTP

In Rail my final goal is to write a Net::HTTP client to connect to my REST API that is returning JSON and parse it, pass it to View , etc....
But first things first!
What is the simplest thing I can start with?
I am looking at this page:http://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html
and I get the impression that if I have one .rb file with these two lines of code in it, it should show me something?
require 'net/http'
Net::HTTP.get('example.com', '/index.html')
url = URI.parse("http://example.com")
req = Net::HTTP::Get.new(url.path)
#resp = Net::HTTP.new(url.host, url.port).start {|http| http.request(req)}
in a view
<%= "The call to example.com returned this: #{#resp}" %>
You could start testing with something like this:
require 'net/http'
response = Net::HTTP.get_response("www.google.com","/")
puts response.body
I'll recommend you take a look at the docs: Net::HTTPSession

How do I get the contents of an http request in Ruby?

In PHP I can do this:
$request = "http://www.example.com/someData";
$response = file_get_contents($request);
How would I do the same thing in Ruby (or some Rails method?)
I've been googling for a half an hour and coming up completely short.
The standard library package open-uri is what you're after:
require 'open-uri'
contents = open('http://www.example.com') {|io| io.read}
# or
contents = URI.parse('http://www.example.com').read
require 'net/http'
Net::HTTP.get(URI.parse('http://www.example.com/index.html'))
Not sure why I didn't find this earlier. Unless there's an better way, I'm going with this!
Using the net/http library as shown:
require 'net/http'
response = Net::HTTP.get_response('mysite.com','/api/v1/messages')
p response.body
In your view try
<%= request.inspect %>

Resources