Ruby On Rails Rescue block - ruby

I have method
common method
def error_notification
<notification_code>
end
whenever the code catches an exception I need to call this method in the rescue block
eg: example
def error_method
begin
<some_code>
rescue => e
error_notification
end
end
Instead of calling all rescue blocks, there is any standard way to write the code

While what you have shown is in no way out of the normal realm of things but you could can certainly DRY this up a bit if you are using it frequently by creating a wrapper for the calls.
Simple Example:
def guard(&block)
begin
block.call
rescue => e
error_notification
end
end
Then use where needed as
def error_method
guard do
some_code
end
end
That being said generally you would want to rescue specific errors not every StandardError but that design decision is up to you.
Additionally if this is specific to controller methods (you didn't really specify), ActiveSupport offers a method called rescue_from that you could utilize as well and would generally be considered more idiomatic in rails application Docs
For Example your setup would look like
class ApplicationController < ActionController::Base
rescue_from StandardError, with: error_notification
private
def error_notification
notification_code
end
end

Related

Ruby Enumerator "Single" method

I really need to make use of something similar to the Single method, which:
Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
Obviously I can add an extension/refinement for convenience.
But does something similar already exists?
Maybe in ActiveSupport or other library?
No, nothing in the Standard Library (nor ActiveSupport, I believe), but easy enough to implement.
module EnumeratorWithSingle
class TooManyValuesException < StandardError; end
class NotEnoughValuesException < StandardError; end
refine Enumerator do
def single
val = self.next
begin
self.next
raise TooManyValuesException
rescue StopIteration
val
end
rescue StopIteration
raise NotEnoughValuesException
end
end
end
module Test
using EnumeratorWithSingle
puts [1].each.single # 1
puts [1, 2].each.single # EnumeratorWithSingle::TooManyValuesException
end

Stop initialization of ruby object

Which is the best practice to not save an object because does not pass certain validations?
I have done this class:
class Articles
attr_reader :doi, :title, :issn
def initialize data, doi_validator: Validators::Doi.new, title_validator: Validators::Title.new, issn_validator: Validators::Issn.new
#doi, #title, #issn = data
#doi_validator = doi_validator
#title_validator = title_validator
#issn_validator = issn_validator
raise_error unless valid?
end
private
def valid?
(
doi_validator.call(doi) &&
title_validator.call(title) &&
issn_validator.call(issn)
)
end
attr_reader :doi_validator, :title_validator, :issn_validator
end
The thing is that instead of raising an error I would like the process of instantiation to be stopped without affecting the flow of the app.
Probably the best way is to check it before initializing the instantiation, but that would complicate pretty much the application. Is there any way you recommend?
If you have something like
article = Articles.new(data)
then there are only two possibilities:
an exception is raised; article = assignment does not happen. You need to catch the exception.
an exception is not raised; article now contains an Article object (possibly invalid).
You could walk the middle ground and make a new class method:
class Article
def self.new_if_valid(*args)
self.new(*args)
rescue InitializationInvalidError
nil
end
end
class InitializationInvalidError < StandardError; end
EDIT: Actually, you could even make it a mixin, it is general enough:
module NilIfInitializationFails
def self.new_if_valid(*args)
self.new(*args)
rescue InitializationInvalidError
nil
end
end
class InitializationInvalidError < StandardError; end
class Article
include NilIfInitializationFails
# ....
end

Catching exceptions while using an external gem

I have written a program that utilizes an external ruby gem. As I am doing a lot of different actions with this, I want to be able to rescue and handle exceptions across the board, instead of implementing it each time I call a method.
What is the best way to do this?
Should I write my own method that simply calls the external gem and also rescues exceptions? Or is there another way to do something like "Whenever an exception of this type comes up anywhere in the program, handle it this way"?
I know that if I wrote the external gem code I could add error handling like that, but that is not feasible.
The basic answer to this is probably to wrap the class you're working with; Ruby allows for a lot of flexibility for doing this since it has method_missing and a pretty dynamic class environment. Here's an example (which may or may not be fatally flawed, but demonstrates the principle:
# A Foo class that throws a nasty exception somewhere.
class Foo
class SpecialException < Exception; end
def bar
raise SpecialException.new("Barf!")
end
end
# This will rescue all exceptions and optionally call a callback instead
# of raising.
class RescueAllTheThings
def initialize(instance, callback=nil)
#instance = instance
#callback = callback
end
def method_missing(method, *args, &block)
if #instance.respond_to? method
begin
#instance.send(method, *args, &block)
rescue Exception => e
#callback.call(e) if #callback
end
else
super
end
end
end
# A normal non-wrapped Foo. Exceptions will propagate.
raw_foo = Foo.new
# We'll wrap it here with a rescue so that we don't exit when it raises.
begin
raw_foo.bar
rescue Foo::SpecialException
puts "Uncaught exception here! I would've exited without this local rescue!"
end
# Wrap the raw_foo instance with RescueAllTheThings, which will pass through
# all method calls, but will rescue all exceptions and optionally call the
# callback instead. Using lambda{} is a fancy way to create a temporary class
# with a #call method that runs the block of code passed. This code is executed
# in the context *here*, so local variables etc. are usable from wherever the
# lambda is placed.
safe_foo = RescueAllTheThings.new(raw_foo, lambda { |e| puts "Caught an exception: #{e.class}: #{e.message}" })
# No need to rescue anything, it's all handled!
safe_foo.bar
puts "Look ma, I didn't exit!"
Whether it makes sense to use a very generic version of a wrapper class, such as the RescueAllTheThings class above, or something more specific to the thing you're trying to wrap will depend a lot on the context and the specific issues you're looking to solve.

Changing ruby method context / calling a method with instance_exec

First, for the short version:
Isn't a method definition just a block? Why can't I do something like:
obj.instance_exec(&other_obj.method(:my_method))
with the goal of running some module method in the context of an instance of a separate class? The method is called, but it doesn't seem to be executed in the context of 'obj', despite the 'instance_exec' call.
The only way I can figure out how to accomplish this is to wrap all of the code of 'my_method' in a proc, then call in the following manner instead:
obj.instance_eval(&other_obj.my_method)
but I'd like to avoid encapsulating all of my module methods in procs.
Now, for the long version:
I'm attempting to create a modularized external provider system, where for any given class/method (generally controller methods,) I can call a corresponding method for a given provider (e.g. facebook).
Since there could be multiple providers, the provider methods need to be namespaced, but instead of simply including a bunch of methods like, for example, 'facebook_invitation_create', I'd like my InvitationsController instance to have a facebook member containing a create method - e.g.
class InvitationsController < ApplicationController
def create
...
# e.g. self.facebook.create
self.send(params[:provider]).create
...
end
end
Furthermore, I'd like the provider methods to not only function as if they were part of the controller itself - meaning they should have access to things like controller instance variables, params, session, etc. - but also to be (mostly) written as if they were part of the controller itself - meaning without any complex additional code as a result of being modularized.
I've created a simplified example below, in which MyClass has a greet method, which if called with a valid provider name (:facebook in this case), will call that providers greet method instead. In turn, the provider greet method accesses the message method of the including class, as if it were part of the class itself.
module Providers
def facebook
#facebook ||= FacebookProvider
end
module FacebookProvider
class << self
def greet
proc {
"#{message} from facebook!"
}
end
end
end
end
class MyClass
include Providers
attr_accessor :message
def initialize(message="hello")
self.message = message
end
def greet(provider=nil)
(provider.nil? or !self.respond_to?(provider)) ? message : instance_exec(&self.send(provider).greet)
end
end
This actually accomplishes almost everything I've previously stated, but I'm hung up on the fact that my provider functions need to be encapsulated in procs. I thought maybe I could simply call instance_exec on the method instead (after removing the proc encapsulation):
instance_exec(&self.send(provider).method(:greet))
...but then it seems like the instance_exec is ignored, as I get the error:
NameError: undefined local variable or method `message' for Providers::FacebookProvider:Module
Is there any way to call instance_exec on a defined method?
(I'm open to suggestions on how to better implement this as well...)
I think this is simpler than you might expect (and I realize that my answer is 2 years after you asked)
You can use instance methods from modules and bind them to any object.
module Providers
def facebook
#facebook ||= FacebookProvider
end
module FacebookProvider
def greet
"#{message} from facebook!"
end
end
end
class MyClass
include Providers
attr_accessor :message
def initialize(message="hello")
self.message = message
end
def greet(provider=nil)
if provider
provider.instance_method(:greet).bind(self).call
else
message
end
end
end
If your provider is a module, you can user instance_method to create an UnboundMethod and bind it to the current self.
This is delegation.
It's the basis for the casting gem which would work like this:
delegate(:greet, provider)
Or, if you opt-in to using method_missing from casting, your code could just look like this:
greet
But you'd need to set your delegate first:
class MyClass
include Providers
include Casting::Client
delegate_missing_methods
attr_accessor :message
def initialize(message="hello", provider=facebook)
cast_as(provider)
self.message = message
end
end
MyClass.new.greet # => "hello from facebook!"
I wrote about what delegation is and is not on my blog which is relevant to understanding DCI and what I wrote about in Clean Ruby
Maybe I'm not following along, but it seems like you are making this harder than it needs to be.
Why not implement a "dispatch" pattern in your class, where you have a hash of provider names and provider methods {:facebook=>"facebook_greet"} and then just "send" the incoming call to the correct handler via "Object#send" (http://ruby-doc.org/core-1.9.3/Object.html#method-i-send)? Send is very fast for dispatching methods, so unlike eval, you should get great performance.
Here's some code to demonstrate the way I'd solve it (assuming I am following along with what you're trying to accomplish):
module TwitterProvider
def providerInit(providers)
#providers[:twitter]="twitter_greet"
super(providers) if defined?(super)
end
def twitter_greet
"Hello Twitter User"
end
end
module FacebookProvider
def providerInit(providers)
providers[:facebook]="facebook_greet"
super(providers) if defined?(super)
end
def facebook_greet
"Hello Facebook User"
end
end
class MyClass
include FacebookProvider
include TwitterProvider
attr_accessor :message
def providerInit(providers)
super(providers) if defined?(super)
end
def initialize(message="hello")
#providers = {}
self.message = message
providerInit(#providers)
end
def greet(provider=nil)
if provider.nil? or !self.respond_to?(#providers[provider])
self.message
else
self.send(#providers[provider])
end
end
end
my_class = MyClass.new
puts my_class.greet
puts my_class.greet(:twitter)
puts my_class.greet(:facebook)
# Output:
# hello
# Hello Twitter User
# Hello Facebook User

Is there a straightforward catchall way to log the methods that are being called on an object in Ruby?

Is there a quick way to track the methods that are being called on an object? Often, when I'm working with a gem at a level just below their public interface, I run into errors that are hard to track down. Ultimately, I end up tracking the object through the source code and keeping everything in my head.
But it would be nice to be able to call something like a #log_method_calls on an object so that, say, all methods called on it get printed to stdout or something. Is there any way to accomplish this?
There are several methods to do it, depending on the situation.
If it' possible to create a new object instead of the observed, you can easily write an observer class using method_missing.
class LogProxy
def initialize obj
#obj = obj
end
def method_missing(name, *args)
puts "#{name} => #{args.to_s}"
#desk.send(name, *args)
end
end
If it's not possible, you still may use alias_method. It's a bit more tricky, but using Module.instance_methods you can chain every method of anything.
Something like:
module Logger
def self.included(mod)
mod.instance_methods.each do |m|
next if m =~ /with_logging/
next if m =~ /without_logging/
mod.class_eval do
define_method "#{m}_with_logging" do |*args|
puts "#{m} called #{args.to_s}"
self.send_without_logging "#{m}_without_logging", *args
end
alias_method "#{m}_without_logging", m
alias_method m, "#{m}_with_logging"
end
end
end
end
TargetClass.send(:include, Logger)

Resources