Changing SMTP Settings at Runtime in Your Rails App

Posted another blog post for raw engineering blog, which helps you to manage your smtp settings dynamically

http://www.raweng.com/blog/2013/03/13/changing-smtp-settings-at-runtime-in-your-rails-app/

JSON responses for 404 and 500 errors in rails

Rails proves to be very much helpful in creating REST APIs. Hence, while you are creating a REST API you would never want to render HTML pages for your 404(page not found) and 500(internal server) errors. This post will help you to return JSON responses instead of the default HTML templates for the same.

Prior to rails 3 you could do this easily and write the code below inside your application controller.

class ApplicationController < ActionController::Base
  rescue_from(ActionController::RoutingError) {
    render :json => {:error_message => "The resource you were looking for does not exist"}
  }
  rescue_from(Exception) {
    render :json => {:error_message => "We're sorry, but something went wrong. We've been notified about this issue and we'll take a look at it shortly."}
  }
end


But with the advent of ActionDispatch in Rails 3.0 all the routing has been moved to rack DSL. Hence, now we cannot catch the ActionController::RoutingError inside of our ApplicationController, as the rack DSL will automatically give the response to the client even before the request reaches your code.

So, in order to achieve the functionality we need, we will have to change the way the routing exceptions are handled inside ActionDispatch::ShowExceptions

Step 1: Create a initializer file show_exceptions.rb inside config/initializers directory, and use the code blow:

# A Custom Exception Handler
# This will call the ErrorsController when a 404 or 500 response is to be sent

require 'action_dispatch/middleware/show_exceptions'

module ActionDispatch
  class ShowExceptions
    private
      def render_exception_with_template(env, exception)
        body = ExceptionsController.action(rescue_responses[exception.class.name]).call(env)
        log_error(exception)
        body[1]['Content-Type']= "application/json; charset=utf-8"
        body
        rescue
          render_exception_without_template(env, exception)
      end

      alias_method_chain :render_exception, :template
  end
end

This will give a call to the appropriate exception handler action inside of ExceptionsController.

Step: 2: Create ExceptionsController, and use the code below

class ErrorsController < ApplicationController
  ERRORS = [
    :internal_server_error,
    :not_found
  ].freeze

  ERRORS.each do |e|
    define_method e do
      message = e == :not_found ? "The request resource was not found" : "We're sorry, but something went wrong. We've been notified about this issue and we'll take a look at it shortly."

      respond_to do |format|
        format.any {render :json => {:error_message => message}, :status => e}
      end
    end
  end
end

That’s all that is required to give a custom json response for 404 and 500 errors for your restful rails applications.

Integrate Google Search Appliance with Rails Application

If you ever want to integrate a Google Search Appliance(GSA) into your rails application, try using the gem rails-gsa.

You can simply download it with the command


gem install rails-gsa

Then after including it in you Gemfile you can start communicating with your GSA. This gem uses the API’s provided by the GSA and provides you search results.

Check out the complete documentation of the gem at https://github.com/rohit9889/rails-gsa

Net::HTTP is not as tough as it appears

Finally got some time for a new post after a long year gap.

Many of us(Ruby Developers) ignore the Ruby Net::HTTP library when we want to communicate with other external applications from our own app. We mostly tend to use certain gems:

and others… but why not use the a native library which is already packaged and delivered with ruby. There is only one advantage of using the external libraries, it makes your code look shorter, and you are happy with it, ARE YOU?? But wait!!! Think about it. You have included an extra library with a bunch of files in your project, which effects the load time of your application.

So here’s what I did to escape from the usage of external libraries and implement the required functionality in my own way.

require "net/http"
require "active_support"

class HTTPRequest
 def self.send_get_request(request_domain,path,data,headers=nil)
 uri = URI.parse(request_domain)
 http = Net::HTTP.new(uri.host, uri.port)

 if headers == nil
 response = http.send_request('GET',path,data)
 else
 response = http.send_request('GET',path,data,headers)
 end

 response.body
 end

def self.send_post_request(request_domain,path,data,headers=nil)
 uri = URI.parse(request_domain)
 http = Net::HTTP.new(uri.host, uri.port)

 if headers == nil
 response = http.send_request('POST',path,data)
 else
 response = http.send_request('POST',path,data,headers)
 end

 response.body
 end

def self.send_put_request(request_domain,path,data,headers=nil)
 uri = URI.parse(request_domain)
 http = Net::HTTP.new(uri.host, uri.port)

 if headers == nil
 response = http.send_request('PUT',path,data)
 else
 response = http.send_request('PUT',path,data,headers)
 end

 response.body
 end

def self.send_delete_request(request_domain,path,data,headers=nil)
 uri = URI.parse(request_domain)
 http = Net::HTTP.new(uri.host, uri.port)

 if headers == nil
 response = http.send_request('DELETE',path,data)
 else
 response = http.send_request('DELETE',path,data,headers)
 end

 response.body
 end

def self.send_request(domain, request_type, request_path, data={}, headers={})
 request_path = "/#{request_path}" unless request_path[0] == "/"
 data = data.to_query if data.is_a?(Hash)
 response = {}
 if request_type == "GET"
 response = send_get_request(domain, request_path, data, headers)
 elsif request_type == "POST"
 response = send_post_request(domain, request_path, data, headers)
 elsif request_type == "PUT"
 response = send_put_request(domain, request_path, data, headers)
 elsif request_type == "DELETE"
 response = send_delete_request(domain, request_path, data, headers)
 end

 ActiveSupport::JSON.decode(response)
 end
end

This code helps me a lot, and lets me have a better control over it, which is not possible in the case of external libraries. Hope this piece of code will be helpful to you guys as well.

UPDATE:

I have created a gem using this, you can install it using the command:

gem install http-requestor

The documentation is available at https://github.com/rohit9889/http-requestor

Making Dynamic Paths for Paperclip

If you ever want to upload and save files in your rails app, you can use this gem Paperclip.

According to the owner of this gem

Paperclip is intended as an easy file attachment library for ActiveRecord. The intent behind it was to keep setup as easy as possible and to treat files as much like other attributes as possible. This means they aren’t saved to their final locations on disk, nor are they deleted if set to nil, until ActiveRecord::Base#save is called. It manages validations based on size and presence, if required. It can transform its assigned image into thumbnails if needed, and the prerequisites are as simple as installing ImageMagick (which, for most modern Unix-based systems, is as easy as installing the right packages). Attached files are saved to the filesystem and referenced in the browser by an easily understandable specification, which has sensible and useful defaults.

This gem proves to be very helpful in attaching and uploading files to your rails-app. You can read the implementation guide on the site. What I am basically focussing on is how can we create dynamic path for storing the files uploaded using Paperclip.

So here’s what my senior colleague Rohit Pal did to workaroud this situation.

Previously we had these settings

has_attached_file :user_image
		    	 :url => "../assets/users/#{self.name}_:basename_:id" + ".:extension",
                 :path => ":rails_root/public/assets/users/#{self.name}_:basename_:id" + ".:extension"

This would save the file in the

RAILS_ROOT/public/assets/users/

directory. But we wanted to store it in

RAILS_ROOT/public/assets/users/#{user_id}

directory. i.e. we wanted to create a separate directory for each and every user in our app.

We tried to use this

has_attached_file :user_image
		    	 :url => "../assets/users/#{self.user.id.to_s}/#{self.name}_:basename_:id" + ".:extension",
                 :path => ":rails_root/public/assets/users/#{self.user.id.to_s}/#{self.name}_:basename_:id" + ".:extension"

But it didn’t work. We also studied many tutorials but they didn’t seem to work for us. After some time Rohit peeped into the Paperclip::Interpolations module and came across the methods basename, id, extension etc. These methods are the one which provide for the tags used in the path and url of paperclip.

So we ended up making a helper in

config/initializers

directory. What we decided to do is, overwrite the Paperclip::Interpolations module and add a method user_id in it, which will retrun us the user id. Here’s the code for the helper.

module Paperclip
    module Interpolations
        def user_id attachment, style_name
            attachment.instance.user_id
        end
    end
end

And now we use this

has_attached_file :user_image
		    	 :url => "../assets/users/:user_id/#{self.name}_:basename_:id" + ".:extension",
                 :path => ":rails_root/public/assets/users/:user_id/#{self.name}_:basename_:id" + ".:extension"

and now it stores the file in

RAILS_ROOT/assets/users/1/

directory. And that’s what we wanted to do.

Thanks. Have a great day. :D