Alllow for "bad" urls in in Rails - ruby-on-rails

I have a simple script which checks for bad url's:
def self.check_prod_links
require 'net/http'
results = []
Product.find_each(:conditions =>{:published => 1}) do |product|
url = product.url
id = product.id
uri = URI(url)
begin
response = Net::HTTP.get_response(uri)
rescue
begin
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
rescue
begin
response = Net::HTTP.get_response("http://" + uri)
rescue => e
p "Problem getting url: #{url} Error Message: #{e.message}"
end
end
end
p "Checking URL = #{url}. ID = #{id}. Response Code = #{response.code}"
unless response.code.to_i == 200
product.update_attribute(:published, 0)
results << product
end
end
return results
end
How can I allow incorrectly formatted urls eg: hkbfksrhf.google.com to not crash the script with the following error:
getaddrinfo: nodename nor servname provided, or not known
I just want the task to run till the end, and print any/all errors that are not a 200 and 301 http response.
Thanks!

Is open-uri an option? It throws an exception when 404s or 500s (or other HTTP exceptions) are encountered, in addition to SocketErrors, which allows you to clean up your code a bit
def self.check_prod_links
require 'open-uri'
results = []
Product.where(:published => 1).each do |product|
url = product.url
id = product.id
failed = true
begin
open URI(url)
failed = false
rescue OpenURI::HTTPError => e
error_message = e.message
response_message = "Response Code = #{e.io.status[0]}"
rescue SocketError => e
error_message = e.message
response_message = "Host unreachable"
rescue => e
error_message = e.message
response_message = "Unknown error"
end
if failed
Rails.logger.error "Problem getting url: #{url} Error Message: #{error_message}"
Rails.logger.error "Checking URL = #{url}. ID = #{id}. #{response_message}".
product.update_attribute(:published, 0).
results << product
end
end
results
end

Related

Microsoft Emotion API for Video Operation Result Not Found - Rails

I'm working with the Microsoft Emotion API for processing emotions in video in a Rails app. I was able to make the call to the API to submit an operation, but now I have to query another API to get the status of the operation and once it's done it will provide the emotions data.
My issue is that when I query the results API, the response is that my operation is not found. As in, it doesn't exist.
I first sent the below request through my controller, which worked great:
#static controller
uri = URI('https://api.projectoxford.ai/emotion/v1.0/recognizeinvideo')
uri.query = URI.encode_www_form({})
request = Net::HTTP::Post.new(uri.request_uri)
request['Ocp-Apim-Subscription-Key'] = ENV['MEA_SubscriptionKey1']
request['Content-Type'] = 'application/octet-stream'
request.body = File.read("./public/mark_zuck.mov")
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
end
# Get response headers
response.each_header do |key, value|
p "#{key} => #{value}"
end
# Get operation location and id of operation
operation_location = response["operation-location"]
oid = operation_location.split("/")[6]
The response of this first call is:
"operation-location => https://api.projectoxford.ai/emotion/v1.0/operations/e7ef2ee1-ce75-41e0-bb64-e33ce71b1668"
The protocol is for one to grab the end of the "operation-location" url, which is the operation id, and send it back to the results API url like below:
# parse operation ID from url and add it to results API url
url = 'https://api.projectoxford.ai/emotion/v1.0/operations/' + oid
uri = URI(url)
uri.query = URI.encode_www_form({})
request = Net::HTTP::Get.new(uri.request_uri)
request['Ocp-Apim-Subscription-Key'] = ENV['MEA_SubscriptionKey1']
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
end
# Get response headers
response.each_header do |key, value|
p "#{key} => #{value}"
end
The result I get is:
"{\"error\":{\"code\":\"Unspecified\",\"message\":\"Operation not found.\"}}"
I get the same result when I query the Microsoft online API console with the operation id of an operation created through my app.
Does anyone have any ideas or experience with this? I would greatly appreciate it.
You do not need parse the "oid" out of "operation-location" header, as it is already the URL you should GET the status.
The following code works for me. Use it to see if you still see the issue.
require 'net/http'
require 'uri'
uri = URI('https://api.projectoxford.ai/emotion/v1.0/recognizeinvideo')
uri.query = URI.encode_www_form({})
request = Net::HTTP::Post.new(uri.request_uri)
request['Ocp-Apim-Subscription-Key'] = '<your key>'
request['Content-Type'] = 'application/octet-stream'
videoFile = File.open("c:\\1mb.mp4", "rb")
request.body = videoFile.read
videoFile.close
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
end
puts response.message
puts response.read_body
# Get response headers
response.each_header do |key, value|
p "#{key} => #{value}"
end
# Get operation location url for subsequent calls
operation_location = response["operation-location"]
operation_url = operation_location
uri = URI(operation_url)
uri.query = URI.encode_www_form({})
loop do
request = Net::HTTP::Get.new(uri.request_uri)
request['Ocp-Apim-Subscription-Key'] = '<your key>'
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
end
puts response.read_body
response_msg = response.read_body
break if response_msg.include?("Succeeded") or response_msg.include?("Failed")
sleep 20
end
puts response.message
puts response.read_body

How do I rescue an exception from inside an Enumerator?

I'm writing an application in Rails and I want to get a huge amount of information from an API – which I'm streaming through an Enumerator object as a CSV export. I want to rescue an error that is called within the Enumerator.
CONTROLLER: Enumerator
def csv_lines( url )
Enumerator.new do |y|
per_page = 200
# Parse parameters and get shelf information
_params = BrowseScraper.get_params(url)
shelf = BrowseScraper.get_preso( _params, 0 )
total_items = shelf['response']['total_results']['all'].to_i
total_pages = ( total_items / per_page.to_f ).ceil
shelf_info = BrowseScraper.crawl_ids( shelf['response']['query']['category'] )
y << BrowseScraper.csv_header(url, shelf_info, total_items, ["Tool ID", "Name", "Price", "URL"])
total_pages.times { |i| y << BrowseScraper.csv_body( _params, per_page, i+1) }
end
end
The following functions are raising errors, but I can't catch them outside of the Enumerator:
MODEL: methods
def self.get_params
response = open(url)
raise if response.code != 200
end
CONTROLLER: Display
def export
url = params[:url]
raise StandardError, "Please enter a Browse URL below" if !url || url.empty?
respond_to do |format|
format.csv do
render_csv(url)
end
format.html { render_csv(url) }
end
rescue => e
flash[:error] = e.message
redirect_to scraper_path
end
private
def render_csv( url )
set_file_headers
set_streaming_headers
response.status = 200
# Rails should iterate this enumerator
self.response_body = csv_lines(url)
end
def set_file_headers( name = "browse_export" )
headers["Content-Type"] ||= 'text/csv'
headers["Content-Disposition"] = "attachment; filename=\"#{name}.csv\""
headers["Content-Transfer-Encoding"] = "binary"
headers["Last-Modified"] = Time.now.ctime.to_s
end
def set_streaming_headers
#nginx doc: Setting this to "no" will allow unbuffered responses suitable for Comet and HTTP streaming applications
headers['X-Accel-Buffering'] = 'no'
headers["Cache-Control"] ||= "no-cache"
headers.delete("Content-Length")
end
Rescuing the error raised in export works. Rescuing an error within the Enumerator works (example:
Enumerator do |y|
begin
y << BrowseScraper.get_params(_params)
rescue => e
Rails.logger.error "Failed to get parameters: #{e.message}"
end
end
How can I rescue an exception outside of the Enumerator so I can properly redirect the user with a flash message? How do I pass the exception from within the Enumerator object? What is it about the Enumerator that isn't letting me rescue it with:
def method
Enumerator do |y|
y << BrowseScraper.get_params(_params)
end
rescue => e
Rails.logger.error "Error in Enumerator is #{e.message}"
end
I think I've figured out what's going on here. When you write code in an Enumerator, the block isn't actually executed within the Enumerator. Therefore, if I add a rescue within the Enumerator, it doesn't matter.
This is because the |y| in Enumerator is actually a yielder object which does the yielding (more on that in the Enumerator documentation or the Enumerator::Yielder documentation.
You have to rescue things beforehand.

check proxy and get timout with ruby-on-rails

I have ruby on rails 4.
How I can to check proxy and get information abot this proxy (timeout and etc.), if it work?
I parse page with nokoriri through proxy.
page = Nokogiri::HTML(open("http://bagche.ru/home/radio_streem/", :proxy => "http://213.135.96.35:3129", :read_timeout=>10))
gem install curb
require 'net/http'
require 'net/ping'
require 'curb'
def proxy_check
#proxies = Proxy.all
url = "ya.ru"
#proxies.each do |p|
proxy = Net::Ping::TCP.new(p.proxy_address, p.proxy_port.to_i)
if proxy.ping?
#resp = Curl::Easy.new(url) { |easy|
easy.proxy_url = p.proxy_address
easy.proxy_port=p.proxy_port.to_i
# easy.timeout=90
# easy.connect_timeout=30
easy.follow_location = true
easy.proxy_tunnel = true
}
begin
#resp.perform
#resp.response_code
rescue
puts "CURL_GET -e- fail "+p.proxy_address
if #resp.response_code == 200
p.proxy_status = 1
p.proxy_timeout = #resp.total_time
else
p.proxy_status = 0
puts "CURL_GET fail "+p.proxy_address
end
end
else
p.proxy_status = 0
puts "ping fail "+p.proxy_address
end
p.save
end
end
returned 200 if availabil.

How to optimize this Ruby code that fetches web content?

We have a Rails 3.2.12 app that fetches data from a partner API by making POST requests. However, we're finding that our code seems to be a bottleneck, as it takes longer to process requests than expected. Can we do anything to speed up the code?
Should we use another XML parser? Is there a faster way to post SSL requests in Ruby?
Thanks!
def ced( ad )
# Set vars
u = 'e'
pw = 'p'
ad = ad.join ','
url = 'https://r.e.com/interface.asp?ResponseType=XML&Command=BC' + '&UID=' + u + '&PW=' + pw + '&DL=' + ad
results = []
# Invoke API command
uri = URI.parse url
http = Net::HTTP.new uri.host, uri.port
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
req = Net::HTTP::Get.new uri.request_uri
resp = http.request req
# Parse API response
resp_xml = Nokogiri.XML resp.body
resp_xml.remove_namespaces!
num_errors = resp_xml.at_xpath('//ErrCount').content
# Any errors?
if num_errors != '0'
error = true
# No errors, process domains
else
resp_xml.xpath('//CheckResult').each do |elem|
results << {
:domain => elem.xpath('D').text.downcase,
:status => case elem.xpath('RRPCode').text
when '210' then 'a'
when '211' then 't'
else
error = true
'error'
end
}
end
end
<truncated>
end

Rails errors[:base] inside class method?

Ok, after almost two hours of searching the web and not finding an answer to my question, I will ask it here.
I have this method in my
class MatchesController < ApplicationController
def import
if Match.find_by_match_id(params[:match_id])
redirect_to matches_url, notice: "Match already imported."
else
Match.import(params[:match_id], params[:league_id])
# error handling here?
redirect_to matches_url, :flash => { :success => "Match imported successfully." }
end
end
in my
class Match < ActiveRecord::Base
def self.import(match,league)
begin
transaction do
uri = URI('https://api.steampowered.com/IDOTA2Match_570/GetMatchDetails/V001/')
params = { :match_id => match,
:key => "MY KEY" }
uri.query = URI.encode_www_form(params)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
resp = http.request(request)
data = resp.body
result = JSON.parse(data)
if result['result']['error']
errors[:base] << "No Match with given ID found"
#self.errors.add_to_base("No Match with given ID found")
break
end
match = result['result']
players = match['players']
pickban = match['picks_bans']
leagueid = match['leagueid']
if league != leagueid
errors.add_to_base("This Match doesn't belong to the selected League")
break
end
end
rescue ActiveRecord::RecordInvalid => invalid
# not yet implemented
end
end
Now when I import a match and it is not found I want to add an error that I can display to the user, but I get this error
undefined local variable or method `errors' for #<Class:0x007fde27cba478>
What am I doing wrong here? And how can I display the error via a flashto the user?
#errors is an instance method, and you're calling it on the Match class. You could write the import method to have a return value of either 'Match imported successfully' or an error message.

Resources