rails rescue function - ruby

i have a products controller on my site and what i decided to do is use the rescue command in rails so that people can't enter products/500 and get the rails error message for a product that doesn't exist. here's what my code looks like
def show
#product = Product.find(params[:id])
#title = #product.name
rescue ActiveRecord::RecordNotFound
redirect_to root_path, :notice => 'No such product'
end
but then i saw some other places where people use begin rescue and else. is the code below a better practice. it works both ways, but i would like to know what the difference is between these two codes
def show
begin
#product = Product.find(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to root_path, :notice => 'No such product'
else
#title = #product.name
end
end

One isolates the thing that causes the exception, one doesn't.
Not really sure if one is a "better practice" or not; I like to keep "things that can go horribly wrong" isolated, but I find begin/rescue/else unwieldy when reading, because I have to "skip ahead" to see what happens if there isn't an exception. Not a lot, but meh.

The reason you'd want to use the begin/rescue/else (and optional ensure) is if you're going to do something else afterwards. In your case, the first of your examples is preferable. It groups the "happy case" logic together, which is most of what you will likely want to focus on, but still leaves it clear what will happen if there is a failure.

Related

Where can I store a mapping method?

I work on an app with Sinatra framework. I would know where the best place is to store a mapping method: in a controller or a decorator. In fact, I import data from a French website that has a French territory, and I want to convert the number territory from number to name.
Here is my method:
def territory_mapping(code)
{
'01' => 'Auvergne-Rhône-Alpes',
'02' => 'Hauts-de-France',
'03' => 'Auvergne-Rhône-Alpes'
}[code]
end
I want to know where I can store this method.
begin
case "my hash's use" do
when "it's for display" then
if "it's a small method"
"put it in a helper for use a controller"
else
"put it in a module and include it using via `helper`"
end
when "it's not for display" then "put it in a helper for use in a route block"
else
"it should go in the class that requires it."
end
rescue NoMethodError => e
e.message = <<~MESSAGE
If it doesn't work because the logic isn't defined
in your views or route blocks then it should go in
the class that requires it."
MESSAGE
ensure
"I get out more so I stop answering this question in Ruby ;-)"
end
In other words, put it in a helper and then you can assess later whether it should go somewhere else.
Regardless, #tadman is right about declaring that example hash as a constant, you should treat access to that as you would to any other constant - if you need it in more than one place then have it the level above in the namespace hierarchy. If it's a lot of data then #Stefan is right to say to load it from somewhere else.

Handling errors with Braintree in Ruby

I am using Braintree to process payments via my web application, no problems so far, plenty of documentation but just a little unsure of how to handle errors in my controller. I don't think I should be looking to display all the error messages back to the user as that could pose a security risk but I would like to handle my errors better than I do now, perhaps capturing a selection of generic errors?
The point of the question here is how would I go about capturing these, within a rescue or create a method that errors would go through and then display some custom messages for certain errors?
At the moment I have a very simple controller action
#result = Braintree::Transaction.sale(
amount: #amount,
payment_method_nonce: params[:payment_method_nonce],
options: {
submit_for_settlement: true
}
)
if #result.success?
redirect_to thank_you_path
else
flash[:alert] = 'Something went wrong while processing your transaction. Please try again!'
gon.client_token = generate_client_token
render :new
end
I just display a generic "Something went wrong" message when #result is not successful.
Are there better ways to deal with this?
The result is an instance of an object, having the whole information about transaction status.
You might extract whatever information you want and print it out to the client.
E.g. to group the messages by the error code, one might use smth like this:
unless #result.success?
flash[:alert] = case #result.transaction.processor_response_code.to_s
when /^2/ then "Contact bank"
else "Something went wrong"
end
...
end

Rails 4 Ignore Error/Exception and Continue

Sorry if it's an easy question, I am pretty new to Ruby.
When users sign up, or login I would like to keep statistics with Redis
def create
#user = User.new(user_params)
if #user.save
$redis.hincrby("2016MMDD", "new_users", 1)
render json: #user
end
end
If for any reason $redis.hincrby fails, is there a way to continue the execution of the code and render the user anyway?
Sure, just wrap the risky code in a begin/rescue/end block that captures the issue and continues execution.
http://rubylearning.com/satishtalim/ruby_exceptions.html. - see handling exceptions.
You might want to research what exceptions to look for, say if redis has gone away, rather than the base Exception catch

How can I rescue a Errno::ECONNRESET

I have a script that spiders a website, its based on Mechanize and seems to be working great except for what seems like an error I can't catch. 'Errno::ECONNRESET' This seems to reset the connection and print the error, but it doesn't seem to raise an exception. What is the best way to deal with this? I will put the program flow in pseudo code below.
while LinksQue.notEmpty
begin
mech.get(LinksQue.nextLink)
rescue Mechanize::ResponseCodeError => e
puts e.response_code
puts "this is a bad link"
rescue Errno::ECONNRESET
#This doesn't work
end
end
Part of my problem is that my method for marking a link as 'visited' or as a 'bad link' is a DB so unless I can update the DB in a rescue block it will just keep trying the same link again and again.

use parameters in routes definition in sinatra

I've been trying for hours and still got no way to configure my routes the way I want to.
What I want to achieve is:
http://fooo.bar/prefix1234
I want to capture everything that starts with specifix prefix.
Pretty easy:
get "/prefix:id" do
puts params[:id]
end
But I don't want it to be a fixed prefix. I want to put the prefix in a config file
settings.rb:
set :prefix, 'pre'
get "/#{settings.prefix}:id" do
puts params[:id]
end
this won't work (undefined method `prefix' for Sinatra::Application:Class (NoMethodError)). I also tried capturing with regex:
before do
#prefix = settings.prefix
end
get %r{#{#prefix}(\d+)} do |id|
puts "Params: #{id}"
end
This doesn't work either (URL will not be captured)
Anyone got anything?
I was able to get your example working almost without modification. This allowed me to do what you described:
before do
#prefix = "test"
end
get %r{#{#prefix}(\d+)} do |c|
puts "#{#prefix} #{c}"
erb :test, :locals => {:id => c}
end
I then ran shotgun to test the output and called /test123. The output was:
test 123
My view also reiterated that this was working properly. If the problem is that the URL is not being captured, you may need to reorganize your structure so that it is more like:
before do
#prefix = "test"
end
get "/#{#prefix}/:id" do
puts "#{#prefix} #{params[:id]}"
erb :test, :locals => {:id => params[:id]}
end
I don't know if the latter is feasible for your application, but if you are not specific enough in the routing, you are leaving yourself open for frequent bad matches. In my experience, the more RESTful your application is, the better off you will be when it comes time to writing these types of operations.
Alternatively, perhaps a YAML file to store your settings in, and then parsed by a script would give you better results for the route. For example, a YAML file with these contents:
prefix: test
And then a helper script that parses that, which would look something like this:
helpers do
def config
#config = YAML.load_file("config.yml")
end
end
You could then replace your before block with this:
before do
#prefix = config["prefix"]
end
My coding tastes make me lean toward using the YAML method, but I think any of these solutions should be viable.
The String/Regexp is generated right away. This works:
require 'sinatra'
set :prefix, '/foo'
get "#{settings.prefix}/bar" do
request.path_info
end

Resources