codedecoder

breaking into the unknown…


Leave a comment

raw sql for rails joins

There are time when ActiveRecord query will not server our purpose and you needs to write raw sql query.

Lets understands with examples when such case arise and how to write raw sql. We will also see how irresponsibly written code crash your system.

One of our application facing a lots of out of memory exception in Heroku and also some of payments not at all getting render in UI as Heroku kills any process which take more than 30 seconds.

Now question is why any request will need more than 30 seconds to load ?.

I was given the task to find the issue and fix it.

The model association in the Application look something as below:

class Payment < ActiveRecord::Base
  has_many :ledgers, dependent: :destroy, autosave: true
  has_many :invoices, through: :ledgers, autosave: true
  has_many :remittances, dependent: :destroy, autosave: true
end

class Ledger < ActiveRecord::Base
  belongs_to :invoice
  belongs_to :payment
end

class Invoice < ActiveRecord::Base belongs_to :customer_information has_many :ledgers has_many :payments, :through => :ledgers
end

class Remittance < ActiveRecord::Base
  belongs_to :payment
end

The business requirement look straight forward, say you have raised invoice for any service and than client will send you Payment for a bunch of invoices. Ledger is the join table between invoice and payment.

Remittance is something like you received extra payment which you return back to Client.
Here the Remittance table do not have direct link with Invoice table. The money returned may be part on a invoice or without it. The Remittance table do have a name column which keep Invoice number and possibly match to a invoice in Invoice table.

Now let see, how current code is written and Problem with it.

Case 1 : Display all the invoices with a payment on UI

Existing Code look as below:

payment_ledgers = payment.ledgers.includes(:invoice).where(matched: true)
payment_ledgers.each do |ledger|
  payment_invoice = ledger.invoice
  if payment_invoice && payment_invoice.remaining_amount > 0        
    customer = payment_invoice.customer_information.customer
    customer_name = customer.legal_name.present? ?  customer.legal_name : customer.name         
    date = payment_invoice.date.strftime("%m/%d/%Y") if payment_invoice.try(:date)
    invoice_hash = {
      number: payment_invoice.number, date: date,
      customer_name: customer_name, remaining_amount: payment_invoice.remaining_amount.to_f.round(2),
      total_amount: payment_invoice.original_amount,applied_amount: payment_invoice.applied_amount,
      id: payment_invoice.id
    }
    invoice_hash.merge!({ledger_id: ledger.id, ledger_applied_amount: ledger.applied_amount.to_f.round(2)})
    invoices << invoice_hash
  end
end

So what developer did here is that. He fetched all the ledgers with a payment and eager loaded invoices so he do not needs to hit a query again on DB.He looping over them as he needs data from 2 other tables also – invoices and customer_informations.

But, this approach have below issue:
It will return say 500 ledgers and than 500 invoices also. So there will be 1000 object occupying your memory. Worst part is you are looping over the ledgers, so the memory will be not released till process complete.

The optimized code look as below:

# Find Payment's Ledger Invoices whose remaining amount greater than zero
# Query will pluck required columns from all the three tables - Ledger, Invoice, CustomerInformation
invoices_data = Ledger.includes(invoice: :customer_information)
                .where("ledgers.payment_id = ?  and matched = ? and invoices.remaining_amount > ?", payment.id, true, 0)
                .pluck('ledgers.id', 'ledgers.applied_amount', 'customer_informations.legal_name', 'customer_informations.name',
                 'invoices.id', 'invoices.number', 'invoices.date', 'invoices.remaining_amount', 'invoices.original_amount', 'invoices.applied_amount'
                )
#Convert invoices_data to array of hash
invoices_data.each do |inv_data|
  invoices << {
    ledger_id: inv_data[0], 
    ledger_applied_amount: inv_data[1].to_f.round(2),
    customer_name: inv_data[2].present? ? inv_data[2] : inv_data[3],
    id: inv_data[4],
    number: inv_data[5], 
    date: inv_data[6],
    remaining_amount: inv_data[7].to_f.round(2),
    total_amount: inv_data[8].to_f.round(2),
    applied_amount: inv_data[9].to_f.round(2)
  }

The above Code with includes generate below sql query:
#The Sql Query above will generate is:
SELECT ledgers.applied_amount, invoices.number, customer_informations.legal_name FROM “ledgers” LEFT OUTER JOIN “invoices” ON “invoices”.”id” = “ledgers”.”invoice_id” LEFT OUTER JOIN “customer_informations” ON “customer_informations”.”id” = “invoices”.”customer_information_id” WHERE “ledgers”.”payment_id” = $1 [[“payment_id”, 4]]

So what we do is:

  1. we removed any looping in ruby code.
  2. We fetched the needed data from 3 tables from DB query itself.
  3. We are not fetching ActiveRecord object but set of info as strings.

You can see that we manged to write DB query with ActiveRecord itself. We do not need any raw sql here…. Rails is great !

Case 2 : Show all Remittances with a payment on UI

Existing Code look as below:

payment_rmh = []
payment.remittances.order('remittance_sequence_number').each do |rmh|
  invoice_id = Invoice.find_by('lower(number) = ? ',rmh.name.downcase).try(:id) if rmh.name.present?
  payment_rmh << {name: rmh.name, amount: rmh.amount,invoice_id: invoice_id}
end

So what developer is doing here is first finding all remittances with Payment, looping over each remittance. Finding Invoice whose number match with remittance name.

Problem here is that Your DB query will become proportional to number of remittances. If 1000 remittances you will make 1000 call to DB. Your system start chocking with memory and execution time will increase.

NOTE: Never ever make DB query within a loop

Now, lets try to optimized the code by eager loading approach in last case:

Remittance.includes(invoice: :customer_information)
Remittance Load (31.0ms) SELECT “remittances”.* FROM “remittances”
ActiveRecord::AssociationNotFoundError: Association named ‘invoice’ was not found on Remittance; perhaps you misspelled it?

So we can see that, includes will not work here unlike last case, as there is no direct association between remittances and invoices. So ActiveRecord failed to generated the Query for us.

Here we need to move out of ActiveRecord queries and build our own raw sql query.

The optimized code look as below:

# Find Payment RMH
rmh_raw_query = "SELECT ri.name, ri.amount, inv.id FROM remittances ri LEFT JOIN invoices inv ON LOWER(ri.name) = LOWER(inv.number) WHERE ri.payment_id = #{payment.id} ORDER BY remittance_sequence_number ASC"
rmh_records = ActiveRecord::Base.connection.exec_query(rmh_raw_query).rows
payment_rmh = rmh_records.map{|rme| {name: rme[0], amount: rme[1].to_f.round(2),invoice_id: rme[2]}}

Here the way to execute raw sql query with rails to call the exec_query method of ActiveRecord::Base.connection.

We have called row method on result returned by exec_query method which basically will return all column you need as an array.

With the above optimization :

  1. 1000 remittances took less than half seconds as compared to 20 seconds earlier.
  2. It will be independent of number of children.Unlike earlier approach, it will always take less than 1 second even if no of remittances reach 1 lakhs or more.
  3. There will be no load on memory.
Advertisements


Leave a comment

Devise session out handling for ajax request rails

Devise work out of box for maintaining user session. But it fails to handle redirect in case of ajax request.

Problem  Description:

  1. User logged in to Rails Application using Devise Auth flow.
  2. Go to fill a form but left for some work and comes back in 15 minutes(divise timeout configured for 15 minutes).
  3. Try to submit the form through ajax call and you show the loder to indicate form got submitted.
  4. The loader keep rotating as the request intercepted in between as unauthorized(401 error in console).

Here Devise did its job and unauthorized the user. The only thing it failed to do is redirect user to login page. If you reload the page you can see that user redirected to login page. So our goal is to exhibit same behavior in ajax request also.

Solution:

The only thing we have to handle is that, make Devise to redirect to login page if user session got expired when we make Ajax call. I looked for the way Devise handling the redirect and got idea from this issue thread on devise. The redirect logic of devise in case of unauthentication is written in the file failure_app.rb .

The redirect logic is written as below in the file

def redirect_url
  if warden_message == :timeout
    flash[:timedout] = true if is_flashing_format?

    path = if request.get?
      attempted_path
    else
      request.referrer
    end

    path || scope_url
  else
    scope_url
  end
end

If you see it do not handle redirect for ajax request i,e of format .js.

The beauty of Ruby is that we can open any class and add our custom behavior. So lets customize the above class. Create a file lib/custom_failure_app.rb and add below line to it.

class CustomFailureApp < Devise::FailureApp 
  def redirect_url 
    if request.xhr? 
      send(:"new_#{scope}_session_path", :format => :js)
    else
      super
    end
  end
end

So we just told Devise that, if xhr request, redirect to login page with format js.

Now we have to configure Devise to use our CustomFailure APP – config/initializer/devise.rb

config.http_authenticatable = false
config.http_authenticatable_on_xhr = false
config.navigational_formats = ["*/*", :html, :js]

config.warden do |manager|
  manager.failure_app = CustomFailureApp
end

So next time whenever ajax request is made on session timeout user will be redirected to users/sign_in.js path.

create view/devise/sessions/new.js.erb file and add below line:

 window.location = "/"

At this point I was expecting that, things will start working now. But it is close but not working as expected. Below is the log:

Completed 401 Unauthorized in 31ms (ActiveRecord: 18.2ms)

Started GET “/users/sign_in.js” for 127.0.0.1 at 2018-07-02 21:26:22 +0530
Processing by Customized::SessionsController#new as JS
Completed 406 Not Acceptable in 3ms (ActiveRecord: 0.0ms)

ActionController::UnknownFormat (ActionController::UnknownFormat):

So, the desired behavior is there, on ajax session expire user got redirected to users/sign_in.js . The error here is because new action of Devise session controller is defined as below:

  # GET /resource/sign_in
  def new
    self.resource = resource_class.new(sign_in_params)
    clean_up_passwords(resource)
    yield resource if block_given?
    respond_with(resource, serialize_options(resource))
  end

It is using respond_with which is not handling .js format. So I overrided it as below:

1 – Changed default devise routes

  devise_for :users, controllers: { sessions: 'customized/sessions' }

2 – Overrided the new method in controllers/customized/sessions.rb .

class Customized::SessionsController < Devise::SessionsController
    
  # GET /resource/sign_in
  def new
    self.resource = resource_class.new(sign_in_params)
    clean_up_passwords(resource)
    yield resource if block_given?
    respond_to do |format|
      format.js
      format.html
    end
  end
end

Now everything working fine. If session got expired while ajax request and user got redirected to login page.


Leave a comment

Subdomain on localhost Rails

Our product is in production and we decided to have a new subdomain which will target a different set of Users. The end goal is to have the same Code base but render different CSS based on subdomain.

Since our App is hosted on Heroku, the first thing I do is checked feasibility of two DNS pointing to same app, I raised the below ticket on heroku:

https://help.heroku.com/sharing/af2a96f9-1559-45c4-9459-db805fe29229

Heroku Confirmed that it is quite easy to do, so now we move ahead with the development.

Here the first problem is to get two URL pointing to our same App in local.

We all know and use below URL in local:

http://localhost:3000

We need another URL as below:

http://MBEportal.localhost:3000

You can achieve this with below steps:

1 – Login as admin user on terminal:

sudo su –

2 – Edit /etc/hosts file

nano /etc/hosts

The above command will open /etc/hosts file for you in terminal.

You will find few lines there, the important one is:

127.0.0.1 localhost

This is the line which basically map localhost to IP 127.0.0.1

Add a new line below it:

127.0.0.1 MBEportal.localhost

This is telling that the new DNS MBEportal.localhost should also map to IP 127.0.0.1

press cntr + x to exist editing

It will ask you to save before existing. Press Y to save the change.

3 -restart your rails server.

Now you can access your localhost at both the below URL

http://localhost:3000/

http://MBEportal.localhost:3000

4 – Parse Subdomain in Controller

So, at this point we have  simulated subdomain behavior. Also both hitting same code base as expected.

But still when I go to controller action and try to see subdomain, it return empty array

request.subdomains -> []

It look like our server treating http://MBEportal.localhost as a single domain.

This can be fixed by adding below line in environment/development.rb file

config.action_dispatch.tld_length = 0

Restart your server again and this time you will get the subdomain from URL

request.subdomains -> [“mbeportal”]

great ! now we can find the subdomain from request object and thus execute different logic or layout or any other thing specific to the particular domain.

Some other detail which you can read from request object are:

request.base_url -> http://MBEportal.localhost:3000
request.host -> mbeportal.localhost
request.domain -> localhost

 


Leave a comment

undefined method `eof?’ for #

Below is one of my API code in my new Rails application

module Api
  module V1
    class VendorOnboardingController < Api::BaseController
      include Concerns::Api::V1::VendorOnboardingApipie
      def enrollment
        result = Parse::Vendor.new(Hash.from_xml(request.body).deep_symbolize_keys!)
        ...remaining code----
      end
    end
  end
end

The API working fine locally and on server running thin as application server.After testing we moved the code to UAT server running on Passenger as application server and the API boomed with below error:

“undefined method `eof?’ for PhusionPassenger::Utils::TeeInput:0x000056122fc69a20”

After breaking a lot of head and changing code with hit and trial method realized the culprit code is request.body in below line of code.

result = Parse::Vendor.new(Hash.from_xml(request.body).deep_symbolize_keys!)

changing it to request.body.read as below fixed the issue.

result = Parse::Vendor.new(Hash.from_xml(request.body.read).deep_symbolize_keys!)

Understanding the Problem:
Rails communicate with application server through Rack.

Infact Rack sits between all the frameworks (Rails, Sinatra, Rulers) and all the app servers (thin, unicorn, Rainbows, mongrel) as an adapter. Now if you see  rack spec it says

The input stream is an IO-like object which contains the raw HTTP POST data. When applicable, its external encoding must be “ASCII-8BIT” and it must be opened in binary mode, for Ruby 1.9 compatibility. The input stream must respond to gets, each, read and rewind.

So in my local or with thin the request body was always coming as a StringIO object, so not causing any problem when the subsequent line of my code operating on it, but with passenger some how, this is not the case so code is breaking.

calling request.body.read will explicitly convert the request body to StringIO object and so fixed the problem.


					
		
	


Leave a comment

image cropping with paperclip

We are using paperclip for managing files and images in our project . I assume you all know how to use paperclip with its default behaviour .

Our user model managing user profile picture with paperclip look as below :

class User < ActiveRecord::Base
	has_attached_file :picture, 
                    styles: { medium: "300x300#", thumb: "80x80#" }, 
                    content_type: ['image/jpeg','image/jpg', 'image/png'],
                    default_url: "/images/:style/missing.png", 
                    whiny: false, 
                    use_timestamp: false
end

I have used few of the option available with has_attached_file method of paperclip . The complete list is available here .

So what it do, when ever user select his picture from UI, paperclip creates different size of it, here medium and thumb size. you can add more style as per your need.

Now we need to enhance user experience and let him to crop the picture also, which is common now a days. So know user have to go through two steps :

STEP 1 : Crop the picture

This step just allow user to select part of the picture he want to upload rather then the whole pic. You can let the user do that by providing 4 input fields crop_x, crop_y, crop_w, crop_h which is basically x cordinate, y cordinate setting the origin from where image is to cut , with the specified width and height.

But this is not user friendly. A lot of libraries are available which can serve the above purpose in better way.

I used croppic which worked well for me . I will write on its usage on some other day. Meanwhile you can try it yourself.

Our end goal in this step is to get user selected portion of image i,e crop_x, crop_y, crop_w, crop_h

STEP 3 : Make Paperclip to work on cropped part.

So, now paperclip should create different size of cropped part rather then the whole image. To make it work we first need to understand its default behaviour of paper clip and its is in this file . Below are the important lines of this file(I have taken only the line need to understood from each method)

module Paperclip
  # Handles thumbnailing images that are uploaded.
  class Thumbnail < Processor
    
    attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options,
      :source_file_options, :animated, :auto_orient
    
    def initialize(file, options = {}, attachment = nil)
      super
      geometry             = options[:geometry].to_s
      @crop                = geometry[-1,1] == '#'
      @target_geometry     = options.fetch(:string_geometry_parser, Geometry).parse(geometry)
      @current_geometry    = options.fetch(:file_geometry_parser, Geometry).from_file(@file)
    end
    
    def crop?
      @crop
    end
    
    def transformation_command
      scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
      trans = []
      trans << "-coalesce" if animated?
      trans << "-auto-orient" if auto_orient
      trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
      trans << "-crop" << %["#{crop}"] << "+repage" if crop
      trans << '-layers "optimize"' if animated?
      trans
    end
  end
end

So you can see that thumbnail class is wrapped up in paperclip module and inherit from processor class . In the initialize method it set @target_geometry and @current_geometry . The main work is handle by transformation_command method . The first line  basically give back scale of the uploaded image and its cropped part . transformation_to method is defined here .

Now we will override these methods of Thumbnail class to suit our need . Read about method overriding in this post .

We are going to create our own custom processor. Lets create a paperclip_processors folder within lib folder and add custom_processor.rb file to it. It will look as below :

module Paperclip
  class CustomCropper < Thumbnail
    def initialize(file, options = {}, attachment = nil)
      super
      if target.crop_w && target.crop_x
        @current_geometry.width  = target.crop_w
        @current_geometry.height = target.crop_h
      end
    end
    
    def target
      @attachment.instance
    end
    
    def transformation_command
      # call crop processing only if user inputs are there
      if target.crop_w && target.crop_x
        crop_command = [
          "-crop",
          "#{target.crop_w}x" \
            "#{target.crop_h}+" \
            "#{target.crop_x}+" \
            "#{target.crop_y}",
          "+repage"
        ]
        crop_command + super
      else
        super
      end
    end
    
  end
end

Our custom_cropper inherit from thumbnail class and override its initialize and transform method. In these method if user inputs for crop is not given, super is called which exhibit the behaviour of Thumbnail without any modification . This condition is put in place as sometime user sync his data from linkedin and at that time crop inputs is not available or say we have created some user in from seed.rb file which face the same issue.

Now our custom processor is defined, we just need to modify the user model to call our custom processor explicitly and so the default thumbnail processor will be not called . The user model will now look as below :

class User < ActiveRecord::Base
	has_attached_file :picture, 
                    styles: { medium: "300x300#", thumb: "80x80#" }, 
                    content_type: ['image/jpeg','image/jpg', 'image/png'],
                    default_url: "/images/:style/missing.png", 
                    whiny: false, 
                    use_timestamp: false,
                    processors: [:custom_cropper]

        attr_accessor :crop_x, :crop_y, :crop_w, :crop_h
end

We have defined attr_accessor for the cordinates and width height.

The controller code will look something like as below

  def upload_profile_pic
    @user.crop_x = params[:imgX1].to_i
    @user.crop_y = params[:imgY1].to_i
    @user.crop_w = params[:imgW].to_i
    @user.crop_h = params[:imgH].to_i
    @user.picture = params[:user][:picture]
    @user.save
  end

That’ s all you need to make your Paperclip custom processor .

 

Resources :

https://github.com/thoughtbot/paperclip

http://www.rubydoc.info/gems/paperclip/Paperclip/ClassMethods

https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/thumbnail.rb

http://www.rubydoc.info/gems/paperclip/Paperclip/Processor


Leave a comment

simple file upload in rails

I have been doing file upload in rails using attachment_fu in initial days and then paperclip since its arrival. But have never used simple file upload i,e without using any gems. Recently I have to redesign the paperclip upload functionality of one of my application(will discuss in some other post), So thought of starting from beginning i,e how simple uploader works, what benefits paperclip or other available gem adds to it etc .

I am assuming you already have some rails 4 application running. We will add photo upload feature to it. This will be our flow.

->There will be a upload button on new photo page.
->User upload a pic using the simple uploaded.
-> On successful upload he will be redirected to show page, displaying the uploaded image.

generate the model and controller with below command on your project root from terminal

$ rails g model Photo pic:attachement
invoke active_record
create db/migrate/20150626122526_create_photos.rb
create app/models/photo.rb

If you see the generated migration file, it has below content

class CreatePhotos < ActiveRecord::Migration
  def change
    create_table :photos do |t|
      t.attachment :pic
      t.timestamps null: false
    end
  end
end

Run migration to add the photos table

$rake db:migrate

Once the migration is complete and you chek the schema.rb file, you will see below detail of the photos table.

  create_table "photos", force: :cascade do |t|
    t.string   "pic_file_name"
    t.string   "pic_content_type"
    t.integer  "pic_file_size"
    t.datetime "pic_updated_at"
    t.datetime "created_at",       null: false
    t.datetime "updated_at",       null: false
  end

So you can see that t.attachement in the migration file get converted into below 4 fields.

t.string “pic_file_name”
t.string “pic_content_type”
t.integer “pic_file_size”
t.datetime “pic_updated_at”

They represent internal property of any attachement. When user upload any file, you need to read these values from params and need to update these fields. Let generate the controller now

$ rails g controller photos new show create.

It will generate new, show and create action in photos controller and the corresponding views.
It will also generate get routes for all these actions.

  get 'photos/new'
  get 'photos/create'
  get 'photos/show'

remove them and replace with resourceful routes.

resources :photos

write the file upload code to the photos/new.html.erb

<%= form_for @photo, :url => photos_path, :html => { :multipart => true } do |form| %>
  <%= form.file_field :pic %>
  <%=form.submit 'upload'%>
<% end %>

This simply provide a file upload field with a upload button, which submit data to create action.

The whole controller code look as below:

class PhotosController < ApplicationController
  before_action :set_photo, only: [:show]

  def show
  end

  def new
    @photo = Photo.new
  end

  def create
    @photo = Photo.new
    @photo_object = params[:photo][:pic]
    @photo.pic_file_name = @photo_object.original_filename
    @photo.pic_content_type = @photo_object.content_type
    respond_to do |format|
      if @photo.save
        file_name_filesystem = @photo.id.to_s + @photo_object.original_filename
        photo_path_on_filesystem = Rails.root.join('public','uploads', file_name_filesystem)
        File.open(photo_path_on_filesystem,'wb') do |file| 
          file.write(@photo_object.read)
        end
        format.html { redirect_to @photo, notice: 'Photo was successfully created.' }
        format.json { render :show, status: :created, location: @photo }
      else
        format.html { render :new }
        format.json { render json: @photo.errors, status: :unprocessable_entity }
      end
    end
  end

  private
  def set_photo
    @photo = Photo.find(params[:id])
  end
end

The points to notice here is the create action. If you put debugger(I use byebug) inside the create action and try to see the params, it look as below

(byebug) pp params[:photo][:pic]
#<ActionDispatch::Http::UploadedFile:0xb3b9be60
@content_type=”image/jpeg”,
@headers=
“Content-Disposition: form-data; name=\”photo[pic]\”; filename=\”user1.jpeg\”\r\nContent-Type: image/jpeg\r\n”,
@original_filename=”user1.jpeg”,
@tempfile=#<File:/tmp/RackMultipart20150626-7518-liirs5.jpeg>>

(byebug) pp params[:photo][:pic].content_type
“image/jpeg”

(byebug) pp params[:photo][:pic].original_filename
“user1.jpeg”

(byebug) pp params[:photo][:pic].tempfile
#<File:/tmp/RackMultipart20150626-7518-liirs5.jpeg>

(byebug) pp params[:photo][:pic].tempfile.path
“/tmp/RackMultipart20150626-7518-liirs5.jpeg”

So you can see that params[:photo][:pic] is an object in itself from which we can get the name of the file, its content etc.

We have first saved file_name and content_type in db, and then write the files content in public/uploads directory of our project. So that when user visit show page next time we will show him the uploaded image.

NOTE: Instead of writing the content to filesystem, you can send it to any API which handle its storage or do whatever with the data you want to do.

Now in show.html.erb we have below code to render the uploaded photo.

 
<% pic_path = @photo.id.to_s + @photo.pic_file_name%> 
<%img src="/uploads/<%=pic_path%>" alt="" />

So from above implementation, now we can see what paperclip or other gem add to it:

-> You do not need to handle writing the uplaoded file to filesystem yourself. Gem will take care of it
-> Gem can handle storing the uploaded file on ThirdParty storage like amazone
-> They can provide further processing on image like creating tumbnail, applying affects etc.


Leave a comment

what are the components of rails ?

rails is responsible for popularity of ruby to a great extent. Rails 4.2.1 is out and it summarizes itself with below line, each words are true to itself.

Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.

As rails is maturing , it is refactoring and restructuring itself. some of the features are removed from core rails library and build into separate gem, which you can include or exclude as per your needs. For example, observers are part of ActiveRecord before 4.0 but after that it is moved to separate gem rails-observer .

Note that rails is gem in itself . It has structured itself in different modules or component , each providing a specific functionality. When you create a new rails application with command below:

$ rails new demoapp

By default all the components get loaded due to below line of code in config/application.rb file

require File.expand_path('../boot', __FILE__)

require 'rails/all'

Bundler.require(*Rails.groups)

module Demoapp
  class Application < Rails::Application
   ----more code ...
  end
end

You are using require ‘rails/all’ , which ask rails to load all the components. Read here about rails booting and loading. But it is unnecessary to load all the components if you do not need it. say your application do not need to send any email, so it is better to not load ActionMailer component or module. Remember that, heavy your application is , more time it will take to load, so keep unwanted thing out.

Well for this you must know what are the components and what it do for you. Below goes the list :

=> ActionMailer :

It manage email support for rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments.

=> ActionPack :

It is responsible for mapping the incoming request i,e URL to a controller action and then rendering the corresponding  view. Internally, it is using rack to communicate with the server. It also manage view caching

=>ActionView :

It is responsible for rendering the view . You may not need it if you expose service as an API rather then a interface .The view rendering is done through external gems like erubis for .erb which is the default(you do not install it but get installed as rails dependency. you will see it if you do gem list on your console) or say haml for .haml templates.

=>ActiveJob :

Active Job is a framework for declaring jobs and making them run on a variety of queueing backends. The basic idea is to provide support for creating job to be run later, which can be then handled with other gem build over it. So to say ActiveJob will provide to infrastructure to create the job, which can be then handled by any of the gem sidekiq or resque or delayed job etc .

=>ActiveModel :

They are responsible for model name introspections, conversions, translations and validations . Basically ActiveModel implementations are ORMs (see ActiveRecord, below), but they can also use non-relational storage like MongoDB, Redis, Memcached or even just local machine memory.

 =>ActiveRecord :

They are responsible to map your model with your ORM database. Remember when you do @user.save, the user detail directly get saved in users table.this mapping is getting handled with ActiveRecord. You do not need it if your model do not interact with database . all the callbacks like before_save etc and associations between model are covered under it.

=>ActiveSupport :

ActiveSupport is a compatibility library including methods that aren’t necessarily specific to Rails. You’ll see ActiveSupport used by non-Rails libraries because it contains such a lot of useful baseline functionality. ActiveSupport includes methods like how Rails changes words from single to plural, or CamelCase to snake_case. It also includes significantly better time and date support than the Ruby standard library.

=>Bundler :

Bundler manages an application’s dependencies through its entire life, across many machines, systematically and repeatably. It is responsible to manage all your gem dependency .

=>Railities :

Railties is responsible for gluing all frameworks together. Overall, it:

->handles the bootstrapping process for a Rails application
->manages the rails command line interface;
->and provides the Rails generators core.

=>sprockets-rails :

 It use to manage your assets pipeline introduced since rails 3.1. Initially it was a core feature of rails but has moved into separate gem sprockets-rails since rails 4.0, so that it can be refactored and develop independently . If you have used it with before rails 4, you have observed the log containing details of all the assets requested which is annoying. but after rails 4.0 when it is moved as separate gem, The configuration option config.assets.logger has been removed. Sprockets will no longer pollute your logs when assets are compiled. Nevertheless, Action Pack will continue to log when assets are requested from your server if they are not precompiled. Also there is increase in performance, now assetes get compiled in about 2 second rather then 8 to 10 second

=> Gems:

They are independent library, which you keep adding as per your need.