Rails Raise Error In Controller
Contents |
and rescuing custom errors in a Rails application. It's often useful to map custom Ruby errors to HTTP response status rails raise custom error codes and have Rails render the appropriate HTML error pages. For example, rails raise error in model you might have a controller that is acting as a simple proxy to a third party service such rails exception types as Twitter or Facebook, and you need any of the HTTP errors encountered when calling those sites to be handled natively by your app. Another use case would be in
Rails Standard Error
a Service-oriented architecture (SOA), where you want any errors in your back end services propagated to your front end web application. In this post we'll demonstrate rescuing status errors in an imaginary proxy controller using the awesome Faraday gem. For the sake of brevity we've omitted the inclusion of tests though in the wild we'd build such a feature using rails raise internal server error TDD and our favourite test weapon, RSpec. Not Found To start, let's handle basic 404 Not Found errors that occur when calling a service. For this we'll need a custom error class that extends StandardError. # lib/errors/not_found.rb module Errors class NotFound < StandardError; end end Faraday provides a neat Rack-esque middleware feature. By creating our own custom middleware we can catch any Faraday 404s and raise our custom error. Furthermore, we can re-use the middleware anytime we need the same behaviour. # lib/errors/raise_error.rb module Errors class RaiseError < Faraday::Response::Middleware def on_complete(env) raise Errors::NotFound if env[:status] == 404 end end end Now for the proxy controller. # app/controllers/proxy_controller.rb class ProxyController < ApplicationController def index connection = Faraday.new(:url => 'http://someservice') do |f| f.adapter Faraday.default_adapter f.use Errors::RaiseError # Include custom middleware end response = connection.get('/some/resource') render :text => response.body end end At this point any NotFounds raised will still result in a 500 Internal Server Error in Rails. To alleviate this let's create a module that uses rescue_from, catches any custom NotFounds and renders the default 404 page. # lib/errors/rescue_error.rb mo
Rails developers. So many different ways to manage control flow, load objects, respond in standard and erroneous ways. My opinion up until recently was "I'll rails exceptions just put a bunch of conditionals in there for different situations."Recently, I've
Rails Raise Unauthorized Exception
been working more on API endpoints and so responding with nice error messages has been more of a priority.
Rails Custom Exception
I started using Exceptions more throughout my code thanks to Avdi Grimm, and I recently wrote and action that I'm particularly proud of. Check it out:# This controller's job is https://wearestac.com/blog/raising-and-rescuing-custom-errors-in-rails to exchange twitter credentials for Shortmail credentialsclass TwitterReverseAuthController < ApplicationController # First, let's make our own subclass of RuntimeError class Error < RuntimeError; end def api_key_exchange # Here are our required parameters. If any are missing we raise an error screen_name = params.fetch(:screen_name) { raise Error.new('screen_name required') } token = params.fetch(:oauth_token) { raise Error.new('oauth_token required') } secret = params.fetch(:oauth_secret){ raise Error.new('oauth_secret http://ngauthier.com/2011/09/using-exceptions-to-manage-control-flow.html required') } # OK now let's authenticate that user. If we can't find a valid user, raise an error @user = User.by_screen_name(screen_name).where( :oauth_token => token, :oauth_secret => secret ).first or raise Error.new('user not found') # Now we'll build a device. I'm not catching an exception on create! here because # It should never fail. (I.e. a failure is actually a 500 because we don't expect it) @device = Device.find_or_create_by_token!( params.slice(:token, :description).merge(:user_id => @user.id) ) render :json => { :api_key => @device.api_key } # Now I can simply catch any of my custom exceptions here rescue Error => e # And render their message back to the user render :json => { :error => e.message }, :status => :unprocessable_entity endendHere are the things I really like about this solution:The happy path is really clear because there's no if/else branchingErrors are really obvious because I'm raising an exception (as opposed to "else render json that complains" which looks like a render which is not immediately apparent as a failure)It's super easy to handle the errors in the same way. Instead of repeating the js
bypass rescue https://codedecoder.wordpress.com/2013/03/26/raising-custom-exception-in-ruby-rails/ Use bypass_rescue to bypass both Rails' default handling of errors in controller actions, and any custom handling declared with a rescue_from statement. This lets you specify details of the rails raise exception being raised, regardless of how it might be handled upstream. Background Given a file named "spec/controllers/gadgets_controller_spec_context.rb" with: class AccessDenied < StandardError; end class ApplicationController < ActionController::Base rescue_from AccessDenied, :with => :access_denied private def access_denied redirect_to "/401.html" end end rails raise error Scenarios standard exception handling using `rescue_from` Given a file named "spec/controllers/gadgets_controller_spec.rb" with: require "rails_helper" require 'controllers/gadgets_controller_spec_context' RSpec.describe GadgetsController, :type => :controller do before do def controller.index raise AccessDenied end end describe "index" do it "redirects to the /401.html page" do get :index expect(response).to redirect_to("/401.html") end end end When I run rspec spec/controllers/gadgets_controller_spec.rb Then the examples should all pass bypass `rescue_from` handling with `bypass_rescue` Given a file named "spec/controllers/gadgets_controller_spec.rb" with: require "rails_helper" require 'controllers/gadgets_controller_spec_context' RSpec.describe GadgetsController, :type => :controller do before do def controller.index raise AccessDenied end end describe "index" do it "raises AccessDenied" do bypass_rescue expect { get :index }.to raise_error(AccessDenied) end end end When I run rspec spec/controllers/gadgets_controller_spec.rb Then the examples should all pass
Here, we will look into creating and raising custom exception in ruby. So, when we need custom exception ??. Well, I give an example from my recent experience for user registration or creation for my application. It will help you to understand when and how to create custom exception, how to raise it and how to rescue it in your code logic. The requirement, is that, the user need to be registered on my site, only if his account also get created on Openam and a certificate created for him on Citadel. So basically, it should be a transaction of four independent calls. => user registration on my site called myfinance.com => user account creation on Openam => certificate creation on citadel => send email to user with login detail If any of them fail, I need to rollback all other. This was my approach: => I will create custom exception for Openam , Citadel, Mailer etc => I will create openam_api.rb, citadel_api.rb, sendmail.rbĀ file, containing the core logic of different feature => I will wrap the openam and citadel call in begin rescue end block => within rescue block I will raise custom exception I have definedĀ for Openam , Citadel etc => I will catch the exception object in create action of my controller and do the rollback stuff STEP 1: creating custom exception Here, You need to understand that, Your custom class, is just like any other class, say for example your user model. It look like this class User < ActiveRecord::Base # you define attribute_accessor # you define methods end You can do all these stuffs in your exception class also and access its attributes and methods on its instance.Here, the instance variable of exception is e in the below code structure begin # some code to be rescued rescue Exception => e # e is the instance of exception being cached so can call all attributes and methods on e end The difference is that, here your class inherit from StandardError rather then ActiveRecord::Base. Lets, create a file my_custom_exception.rb in lib folder, so that it get compiled when ever the server is started. The file co