rescue Nokogiri error - ruby-on-rails

I've a simple script that looks at Twitter username and gets me the location. But some of the username doesn't exist and I get error:
/usr/lib/ruby/1.8/open-uri.rb:277:in `open_http': 404 Not Found (OpenURI::HTTPError)
I've tried to rescue it, but I can't to make it work. Can anyone help? Thanks
a = []
my_file = File.new("location.txt", 'a+')
File.open('address.txt', 'r') do |f|
while line = f.gets
url = "http://twitter.com/#{line}"
doc = Nokogiri::HTML(open(url, 'User-Agent' => 'ruby'))
doc.css("#side #profile").each do |loc|
my_file.puts "http://twitter.com/#{line} #{loc.at_css(".adr").text}"
puts line
end
end
end
I also need help rescuing another error:
twitter.rb:14: undefined method `text' for nil:NilClass (NoMethodError)
Thanks.

Double quotes inside the other double quotes! Use single quotes for the call to at_css():
my_file.puts "http://twitter.com/#{line} #{loc.at_css('.adr').text}"

Turns out a simple rescue StandardError did the trick.

Related

Can't catch ActiveRecord::RecordNotFound with rescue

I'm new to Ruby, please bear with me if this is a stupid question, or if I'm not following the best practice.
I'm finding an object in the DB using find(), and expect it to throw RecordNotFound in case the object of the id does not exist, like this.
begin
event = Event.find(event_id)
rescue ActiveRecord::RecordNotFound => e
Rails.logger.debug "Event does not exist, id: " + event_id
return {
# return "unauthorized" to avoid testing existence of event id
# (some redacted codes)
}
end
But somehow it is not caught (the log in the rescue block is not printed) and the entire program just return internal server error. Here's the stack trace:
Completed 500 Internal Server Error in 22ms (ActiveRecord: 1.0ms)
ActiveRecord::RecordNotFound (Couldn't find Event with 'id'=999):
lib/sync/create_update_event_handler.rb:78:in `handleRequest'
app/controllers/sync_controller.rb:36:in `block in sync'
app/controllers/sync_controller.rb:31:in `each'
app/controllers/sync_controller.rb:31:in `sync'
Rendering /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (6.4ms)
Rendering /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.3ms)
Rendering /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.9ms)
Rendered /usr/local/rvm/gems/ruby-2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (36.6ms)
The only thing I can think of is there are two different ActiveRecord::RecordNotFound, and I'm catching the wrong one, but I don't know if it is the case or how I can verify it.
What did I do wrong?
======================================
Update
The problem is in the rescue block, I was concatenating event_id (an integer) to a string.
The RecordNotFound exception was indeed caught, but when the type error was thrown in the rescue block, the wrong error message was printed.
You won't get an error if you do
event = Event.find_by(id: event_id)
In this case if the record can't be found by ID it will just event == nil be nil.
In this case if the record can't be found by ID it will just event == nil be nil.
The code you pasted works fine for me. If you don't see output in the log, check your environment and log level settings INFO, WARN, DEBUG etc. 500 error indicates some kind of controller action raising the error.
see Set logging levels in Ruby on Rails
To be sure your rescue block is executing try doing something besides log. If you're running a development server you can try :
begin
event = Event.find(event_id)
rescue ActiveRecord::RecordNotFound => e
msg = "Event does not exist, id: #{event_id.to_s}"
Rails.logger.debug msg.
puts msg
binding.pry # if you have gem 'pry' in your development gems.
File.open('test.log', 'w') {|f| f.write msg} #check if this appears in root of your app
return {
# return "unauthorized" to avoid testing existence of event id
# (some redacted codes)
}
end
UPDATE: I changed the string interpolation according to your answer. You can also call .to_s inside interpolation instead of closing quotes and appending.
Turned out the error message is wrong.
The problem is that I was concentating the event_id (an integer) to a string.
But somehow Rails prints out the RecordNotFound exception.
The problem is fixed by replacing
Rails.logger.debug "Event does not exist, id: " + event_id
with
Rails.logger.debug "Event does not exist, id: " + event_id.to_s
Thanks #lacostenycoder for bringing my attention to the error message.
#event = Event.find(params[:id]). you should write instead params[:id] .That's the cause of an error.

Backtrace Silencer not working

In my Rails app, I have set up the following backtrace silencer, as suggested by Michael Hartl in his Rails tutorial:
Rails.backtrace_cleaner.add_silencer { |line| line =~ /rvm/ }
But still I get all the noise I intended to filter out:
7:13:55 - INFO - Running: test/controllers/tags_controller_test.rb
Started
ERROR["test_should_get_index", TagsControllerTest, 0.45206]
test_should_get_index#TagsControllerTest (0.45s)
ActionController::UrlGenerationError:
ActionController::UrlGenerationError: No route matches {:action=>"index", :controller=>"tags"}
/Users/chris/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-4.1.6/lib/action_dispatch/journey/formatter.rb:39:in `generate'
/Users/chris/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-4.1.6/lib/action_dispatch/routing/route_set.rb:599:in `generate'
Clearly the string "rvm" is present in the last two lines. But still they show up. Changing the string to ".rvm" didn't make any difference.
This is because of https://github.com/vipulnsward/rails/blob/ecc8f283cfc1b002b5141c527a827e74b770f2f0/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L155-L156
Since application_trace is empty(This is because error is not from user code but route error), we are falling back to framework_trace, which does not filter it (it filters only noise).
You can solve it with creating your own log_formatter. In your development.rb and/or test.rb add
config.log_formatter = SilentLogger.new
config.log_formatter.add_silencer { |line| line =~ /rvm/ }
And create simple class in models with only method call required. There you can modify your backtrace as you wish.
class SilentLogger
def initialize
#silencers = []
end
def add_silencer(&block)
#silencers << block
end
def call(severity, timestamp, progname, msg)
backtrace = (String === msg) ? "#{msg}\n" : "#{msg.inspect}\n"
return backtrace if #silencers.empty?
#silencers.each do |s|
backtrace = backtrace.split("\n").delete_if { |line| s.call(line) }
end
backtrace.join("\n")
end
end
Your logs show /.rvm/ your setting /rvm/ - can this be the cause?
Give it a try and dont forget to stop / restart the server.

Rails/unicode issue

I have a bit of my Ruby/Rails (Ruby 2.0.0p195, Rails 3.2.13) project that works as a proxy; that is, you pass it a URL, it goes out and fetches the page, and presents it to you. This generally works as expected, but it seems to munge certain characters (such as è).
A simplified version of the controller is this:
class HomeController < ApplicationController
def geoproxy
require 'net/http'
require 'timeout'
rawurl = CGI::unescape(params[:url])
fixedurl = rawurl.gsub('\\', '%5C') # Escape backslashes... why oh why???!?
r = nil;
status = 200
content_type = ''
begin
Timeout::timeout(15) { # Time, in seconds
if request.get? then
res = Net::HTTP.get_response(URI.parse(fixedurl))
status = res.code # If there was an error, pass that code back to our caller
#page = res.body.encode('UTF-8')
content_type = res['content-type']
end
}
rescue Timeout::Error
#page = "TIMEOUT"
status = 504 # 504 Gateway Timeout We're the gateway, we timed out. Seems logical.
end
render :layout => false, :status => status, :content_type => content_type
end
end
The corresponding view is quite simple:
<%= raw #page %>
When I use this proxy to fetch XML containing an è (for example), I get the following error:
Encoding::UndefinedConversionError in HomeController#geoproxy
"\xE8" from ASCII-8BIT to UTF-8
This error occurs at the following line:
#page = res.body.encode('UTF-8')
If I remove the .encode(), the error is resolved, but my XML contains a placeholder instead of the è.
How can I get my project to display the XML properly?
Could you check if the following code works for you? I was able to fix similar problem of mine with it.
#page = res.body.force_encoding('Windows-1254').encode('UTF-8')

ruby net_dav sample puts

I'm trying to put a file on a site with WEB_DAV. (a ruby gem)
When I follow the example, I get a nil exception
#### GEMS
require 'rubygems'
begin
gem "net_dav"
rescue LoadError
system("gem install net_dav")
Gem.clear_paths
end
require 'net/dav'
uri = URI('https://staging.web.mysite');
user = "dave"
pasw = "correcthorsebatterystaple"
dav = Net::DAV.new(uri, :curl => false)
dav.verify_server = false
dav.credentials(user, pasw)
cargo = ("testing.txt")
File.open(cargo, "rb") { |stream|
dav.put(urI.path +'/'+ cargo, stream, File.size(cargo))
}
when I run this I get
`digest_auth': can't convert nil into String (TypeError)
this relates to line 197 in my nav.rb file.
request_digest << ':' << params['nonce']
So what I'm wondering is what step did I not add?
Is there a reasonable example of the correct use of this gem? Something that does something that works would be sweet :)
SIDE QUESTION: Is this the correct gem to use to do web_DAV? It seems an old unmaintained gem, perhaps there's something used by more to accomplish the task?
Try referencing the hash with a symbol rather than a string, i.e.
request_digest << ':' << params[:nonce]
In a simple test
baz = "baz"
params = {:foo => "bar"}
baz << ':' << params['foo']
results in the same error as you're getting.

code to ping websites works sometimes

I'm testing out a piece of code to ping a bunch of websites I own on a regular basis, to make sure they're up.
I'm using rails and so far I have this hideous test action that I'm using to try it out (see below).
The problem though, is that sometimes it works, and other times it won't ... sometimes it runs through the code just fine, other times, it seems to completely ignore the begin/rescue block ...
a. I need help figuring out what the problem is
b. And refactoring this to make it look respectable.
Your help is much appreciated.
edit 1: Here is the updated code, sorry it took so long, pastie.org was down since yesterday http://pastie.org/927201
Its still doing the same thing ... skipping the begin block (because it only updates up_check_time) ... however if one of the sites times out, it actually updates everything (check_msg, code etc) correctly ... confusing, yeah?
require 'net/http'
require 'uri'
def ping
#sites = NewsSource.all
#sites.each do |site|
if site.uri and !site.uri.empty?
uri = URI.parse(site.uri)
response = nil
path = uri.path.blank? ? '/' : uri.path
path = uri.query.blank? ? path : "#{path}?#{uri.query}"
begin
Net::HTTP.start(uri.host, uri.port) {|http|
http.open_timeout = 30
http.read_timeout = 30
response = http.head(path)
}
if response.code.eql?('200') or response.code.eql?('301') or response.code.eql?('302')
site.up = true
else
site.up = false
end
site.up_check_msg = response.message
site.up_check_code = response.code
rescue Errno::EBADF
rescue Timeout::Error
site.up = false
site.up_check_msg = 'timeout'
site.up_check_code = '408'
end
site.up_check_time = 0.seconds.ago
site.save
end
end
end
You currently have an empty rescue block for Errno::EBADF so if that exception is raised then you will not be setting site.up to false.
Also, a couple of other minor improvements:
Instead of if site.uri and !site.uri.empty? you can use:
next if site.uri.nil? or site.uri.empty?
to skip that iteration of the each loop and avoid indenting the code by an additional level.
And:
if response.code.eql?('200') or response.code.eql?('301') or response.code.eql?('302')
site.up = true
else
site.up = false
end
can be written more concisely:
site.up = ['200', '301', '302'].include? response.code
If you tidy up the code with some of these tips then it might help narrow down the problem.
Here's a snippet from one of my programs, maybe it helps:
urls.each_with_index do |url, idx|
print "Processing URL #%04d: " % (idx+1)
uri = URI.parse(url)
response = nil
begin
Net::HTTP.start(uri.host, uri.port) do |http|
response = http.head(uri.path.size > 0 ? uri.path : "/")
end
rescue => e
puts "#{e.message} - #{url}"
next
end
# handle redirects
if response.is_a?(Net::HTTPRedirection)
new_uri = URI.parse(response['location'])
puts "URI redirects to #{new_uri}"
next
end
puts case response.code
when '200' then ...
when '404' then ...
else ...
end
end
The only thing that I can think of is that you are getting some other exception in your begin block. Since you are only explicitly rescuing Errno::EBADF, Timeout::Error it would appear that your begin and rescue got skipped. You might be able to verify this by getting rid of Errno::EBADF, Timeout::Error and just having a plain rescue, then put the following in your rescue block
logger.info(">>Exception was: "+$!)
Then look in your logs to see what exceptions you are getting.
If you are monitoring your servers why not use Nagios? it's free and also has some Ruby support, Here and Here.
EDIT:
Ruby GEM: http://hobodave.com/2010/01/10/simple-nagios-probes-in-ruby/

Resources