codedecoder

breaking into the unknown…


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

Advertisements


Leave a comment

pagination missing rails_admin view

Recently, I have integrated, the current version of rails_admin 0.4.9 and found that, everything working fine except, the pagination link. The pagination link not appearing on any of the index view of the rails_admin. I tried hard to google the solution, but failed and finally posted my problem here on stack overflow. But, since no answer coming from stack overflow, I tried to dig deeper in the problem myself. So this is how I followed

first thing first, check the code, which render the rails_admin index view. my target file is rails_admin-0.4.9/app/views/rails_admin/main/index.html.haml  of the rails_admin gem. On the first look, itself I got the problem, they have put the pagination within if else condition, in their this recent commit

if @objects.respond_to?(:total_count)

.....pagination code...

else

......without pagination code......

end

Infact, this change has resulted in a known issue for rails_admin reported here . The thread also have the solution. So what is happening due to the above change. The code is trying to check, if the object have total_count method defined on it or not. The gem owner has introduced this change to prevent “undefined method total_count” . unfortunately, it solve the error at the cost of escaping pagination. So now, we know the cause. The Solution is to define total_count method on the object . The objects here is returned from will_paginate gem. so we are going to add the total_count method to it through monkey patching . monkey patching is nothing but adding new methods or overriding the existing one, by maintaining same hierarchy of class and module in your application. Say, to solve our problem, we will monkey patch will_paginate module as below.

create a file with any name say will_paginate_patch.rb in /config/intializer folder of your app, and add below line to it.

if defined?(WillPaginate)
  module WillPaginate
    module ActiveRecord
      module RelationMethods
        def per(value = nil)
          per_page(value)
        end
        def total_count()
          count
        end
      end
    end
    module CollectionMethods
      alias_method :num_pages, :total_pages
    end
  end
end

so, if you see the /lib/will_paginate/active_record.rb file of will_paginate gem, you can see that, they already have per_page and count method defined in it, but there is no total_count or per method in it, so the above patch will add the method and solve our problem.


Leave a comment

rails_admin custom logout link

rails_admin generally work with devise. Its logout link simply destroy the user session. But in my application, although I am using devise, the actual authentication is done on OPENAM. If user is authenticated on OPENAM, I used to sign_in the user with devise. Similarly, the logout link on my application go to my custom action, where I destroy the user session on OPENAM and then call devise sign_out method to destroy the devise user session.

So basically, on rails_admin, I want to change the logout url from “/users/sign_out” which call devise  sessions#destroy action to “/logout“, which will call my custom logout method.

Unfortunately, I do not find any configuration option provided by rails_admin to this. I do find a thread here , which talked of the configuration option introduced for logout, but some how it do not worked for me, may be the changes are not present in current rails_admin 0.4.3.

The workaround, is to replace the link on page load for rails admin. You can add custom js or css to rails_admin. It is explained here .

In our case to change, the rails_admin logout link follow the below steps :

STEP 1: create rails_admin js override file

add ui.js file at below location in your application –

app/assets/javascripts/rails_admin/custom/ui.js # any js code in this file will override, those set in rails_admin

STEP 2 : write the js code to replace the logout link.

jQuery(function(){
      $(document).ready(function(){
      #It will check that the page do contain the link to be replaced
      if($("a[href='/users/sign_out']").length > 0){ 
      $("a[href='/users/sign_out']").attr("href", "/logout")
      }
    })
 })

that’s all, now whenever user click on logout link, it will take him to your custom logout action.

STEP 3: Adding Static links to Rails Admin

Though not related to logout link, I want to mention it that you can add any static link to rails Admin Navigation.

It is explained here .


7 Comments

Bundler::GitError with passenger

Recently, I get into a strange problem. I’am using jqgrid_for_rails gem for jqgrid implementation. There are some changes in the gem which is available in the master branch of github but not in the gem published or rubygems.org, I think they have still not released the new changes to rubygems.org. So, I linked the source code of the gem to its git repository in my Gemfile as below

gem 'jqgrid_for_rails' # it will fetch the gem from rubygems.org. I replaced it with the below line

gem 'jqgrid_for_rails', :git => 'http://github.com/Juanmcuello/jqgrid_for_rails.git' # it will 
fetch the gem from its git repository

I run bundle install , which installed the gem and everything worked fine in development. I pushed the code to production. restart nginx and passenger, but my application breakdown with below error notified by passenger,

http://github.com/Juanmcuello/jqgrid_for_rails.git(at master) is not checked out. Please run bundle install(Bundler::GitError)

Bundler::GemError

SO, the error is obvious, and they are also suggesting the solution. Well, I have already run bundle install any way I run it again

$ bundle install

.

Using jqgrid_for_rails (1.0.1) from http://github.com/Juanmcuello/jqgrid_for_rails.git (at master) # it means the gem is allready there

$ bundle show jqgrid_for_rails
/home/arun/Projects/third-pillar/vendor/bundle/ruby/1.9.1/bundler/gems/jqgrid_for_rails-62969c07e4ca # so the gem is installed

But still the error persists. No doubt, Passenger is not able to read the installed gem from rvm when installed with source as git repository, this may be because, when you install a gem from rubygems.org it get installed in gems folder of your gemset but if you specify some other source as we have done for jgrid_for_rails above the gem will get installed into bundler folder of your gemset. Somehow passenger do not able to read it from there. I tried without passing the git source and running bundle install again and things work this time.

But, My purpose is not solved as my application is UP but I can’t use jqgrid_for_rails gems feature which is must for me. So I restored back my gemfile and looking deep for some more solution. I got the solution in bundler site itself here

SOLUTION :  After deployment of your code run bundle install – -deployment instead of bundle install

when you run bundle install, the bundler install the gem into gems folder of your gemset i,e the gem resides in rvm of your system

when You run bundle install – -deployment  the bundler install the gems locally in your project’s vendor/bundle/ruby/1.9.1/gems folder i.e the gems are always available in your project and bundler will tell passenger to look for gems from this folder instead of RVM


2 Comments

devise_confirmable : email not send and Net::SMTPAuthenticationError problem

Devise is a great gem to manage user authentication. You can also implement user confirmation using this i,e a confirmation email will be send when a user registered and he will we able to login only after clicking to that email. By default devise_confirmable module is inactive for devise but you can activate it with few changes. Devise provide different support for user confirmation like triggering email, validating confirmation etc. The detail list of methods is documented here. I will just list here the changes which will make you existing devise authentication to support devise_confirmable. I am assuming that the model you are authenticating with devise is User. I will underline any modification we made to existing code

STEP 1: Add filed required for  devise_confirmable  to user model

If you see Your user migration, you will find different devise introduced fields. many of the field which is not needed by default is commented out. Below is the default migration generated by devise for user

class DeviseCreateUsers < ActiveRecord::Migration   
    def change    
      create_table(:users) do |t|       
      ## Database authenticatable       
      t.string :email,              :null => false, :default => ""
      t.string :encrypted_password, :null => false, :default => ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, :default => 0
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at

      ## Token authenticatable
      # t.string :authentication_token

    end

    add_index :users, :email,                :unique => true
    add_index :users, :reset_password_token, :unique => true
    # add_index :users, :confirmation_token,   :unique => true
    # add_index :users, :unlock_token,         :unique => true
    # add_index :users, :authentication_token, :unique => true
  end
end

So you can see that field needed for Confirmable, Lockable and Token authenticatable module of devise is commented out as they are not the default. whenever you want to activate any module you need to add those fields to the users table. You can see that for authenticable module we need 4 more  field and then add index to that. So we will define a new migration and add the required field

class AddAuthenticationTokenToUser < ActiveRecord::Migration   
  class AddConfirmableToUsers < ActiveRecord::Migration   
    # Note: You can't use change, as User.update_all will fail in the down migration   
    def up     
      add_column :users, :confirmation_token, :string     
      add_column :users, :confirmed_at, :datetime     
      add_column :users, :confirmation_sent_at, :datetime     
      add_column :users, :unconfirmed_email, :string # add it Only if are using reconfirmable 

      add_index :users, :confirmation_token, :unique => true
     end

    def down
      remove_column :users, :confirmation_token, :confirmed_at, :confirmation_sent_at
      # remove_column :users, :unconfirmed_email # Only if using reconfirmable
    end
 end

run the migration to introduce the newly added filed rake db:migrate

STEP 2: Modifying the model

In model we will do below modification

class User < ActiveRecord::Base

  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable,
    :validatable, :timeoutable, :omniauthable , :token_authenticatable, :confirmable 
    # to use devise_confirmable module, registerable and confirmable module must be there
end

STEP 3: Modifying the config/intializers/devise.rb

devise confirmable module implement reconfirmable by default i,e if a user has not clicked the confirmation link and try to login then it will send the confirmation link again, if you do not want this, you can deactivate it by setting false in config/intializers/devise.rb as below

config.reconfirmable = false

STEP  4: Setting up smtp server

The mailer setting is written in individual environment file. For example, for development we write it in config/environments/development.rb. My file look like this(Iam showing only mailer code)

config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = false
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default :charset => "utf-8"

config.action_mailer.smtp_settings = {
address: "smtp.gmail.com", #this is you remote mail server, if you do not specify it rails will use 
mail server installed in your localhost
port: 587, # the port at which mail server is running, for local host it is at 25
domain: "example.com", # just giving a domain name to you smtp server, you can use any name
authentication: "plain", # If your mail server requires authentication, you need to specify 
the authentication type here.This is a symbol and one of :plain, :login, :cram_md5.
enable_starttls_auto: true,
user_name: "xyz@yopmail.com",
password:  "test123"
}

STEP 5: See it working.

restart the server, go to signup page and register a user. Strange, your user did’nt get any email at say arun@yopmail.com with which he has registered. But when you see the console, you do see that email is getting delivered.

Problem 1: confirmation email not really getting delivered to user although he can see it triggered in terminal log.

Solution : This is happening because, you are running your app in development mode for which mail delivery is disabled by default . In your setting in step 4, you should change the value of the below line to true
config.action_mailer.perform_deliveries = false # it is preventing real delivery of the email
config.action_mailer.perform_deliveries = true # now your email will get delivered

Restart the server and try to register a user again.. Now If you are using setting of step4 ,you will encounter the next error

Problem 2: Net::SMTPAuthenticationError in Devise::ConfirmationsController

Solution : The problem here is that devise do authentication of the user you have passed in setting of step 4 i,e the username and password you have passed in step 4 should be a real gmail user. Note that you have set dummy value like user_name: “xyz@yopmail.com”, password:  “test123”. This user_name and password should be replaced with
a real gmail account detail. I put user_name: arunprojects@gmail.com and password: mypassword and it start working 🙂

So, Now when a user register himself, he will get a confirmation email, when he will click the email link he will able to login otherwise get message, “You have not activated your account” but the problem here is that, all the user existed earlier will not able to login as at the time of there creation. confirmation module is not activated so they, did’nt get the email. But now since devise_confirmable module is active those user will not bale to login. We need to fix this. We will write a rake task for this in next step

STEP 6 : writing rake task to update existing user as confirmed

Create a user.rake file in lib/tasks folder of your app and below line to it

namespace :users do
  desc "set all old user as confirmed by devise confirmable module"
  task :confirm_existing_user => :environment do
    User.update_all(:confirmed_at => Time.now)
  end
end

Now go to condole and run below command

$ rake users:confirm_existing_user # it will update all user as confirmed


1 Comment

devise login with authentication_token

Devise is a great gem to manage user authentication. You can also authenticate a user i,e make user to login with authentication token. By default token_authentication is inactive for devise but you can activate it with few changes. Devise provide different support for token authentication like creating tokens, validating with passed token, expiring the token etc. The detail list of methods is documented here. I will just list here the changes which will make you existing devise authentication to support token based authentication. I am assuming that the model you are authenticating with devise is User. I will underline any modification we made to existing code

STEP 1:  Add authentication_token field to user model

If you see Your user migration, you will find different devise introduced fields. many of the field which is not needed by default is commented out. Below is the default migration generated by devise for user

class DeviseCreateUsers < ActiveRecord::Migration   def change     create_table(:users) do |t|       ## Database authenticatable       t.string :email,              :null => false, :default => ""
      t.string :encrypted_password, :null => false, :default => ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, :default => 0
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at

      ## Token authenticatable
      # t.string :authentication_token

    end

    add_index :users, :email,                :unique => true
    add_index :users, :reset_password_token, :unique => true
    # add_index :users, :confirmation_token,   :unique => true
    # add_index :users, :unlock_token,         :unique => true
    # add_index :users, :authentication_token, :unique => true
  end
end

So you can see that field needed for Confirmable,  Lockable and  Token authenticatable module of devise is commented out as they are not the default. whenever you want to activate any module you need to add those fields to the users table. You can see that for authenticable module we need one field and then add index to that. So we will define a new migration and add the required field

class AddAuthenticationTokenToUser < ActiveRecord::Migration   
  def change     
    add_column :users, :authentication_token, :string     
    add_index  :users, :authentication_token, :unique => true
  end
end

run the migration to introduce the newly added filed rake db:migrate

STEP 2: Modifying the routes.rb for devise

Since, authentication_token concept is basically use to authenticate user from outside i,e say you sent user a email containing the activation link containing the token, so when he click the link he directly get loged in. Similarly, If a User want to access your site from some other site he can access it by authenticating himself by passing proper token in signin url. We need to tell Devise what will be the name of the key which will hold the authentication_key let us call it authentication_key itself

devise_for :users, :token_authentication_key => 'authentication_key'

STEP 3: Modifying the model

In model we will do below modification

class User < ActiveRecord::Base

  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable,
    :validatable, :timeoutable, :omniauthable , :token_authenticatable # the underline is 
    added to existing code, it will activate authenticable module of Devise

  before_save :ensure_authentication_token # whenever a user is saved i,e created or updated it
  will see that a unique authentication token get created if not already exist

end

STEP 4: Modifying the Application controller

Now we are ready to go, Devise will take care of everything. It provide a empty method after_token_authentication as hook in which we will do our stuff if the user is authenticated. So we will set a before_filter on this method.

class ApplicationController < ActionController::Base

  before_filter :after_token_authentication # it is empty hook provided by devise i,e 
  once user is successfully authenticated with the token devise look for this method , 
  and execute the code there

  def after_token_authentication
    if params[:authentication_key].present?
      @user = User.find_by_authentication_token(params[:authentication_key]) # we are finding 
      the user with the authentication_key with which devise has authenticated the user
      sign_in @user if @user # we are siging in user if it exist. sign_in is devise method 
                               to sigin in any user
      redirect_to root_path # now we are redirecting the user to root_path i,e our home page
    end
  end

end

STEP 5: See it working.

Let ,My application is my_app.com, one of the user have the  authentication token “xyz1234rst” , when he will type below url in browser, he will get loged in and redirected to root_path

http://my_app.com/users/sign_in? authentication_key=xyz1234rst

The user is at the home page of the Site…So great….Its working 🙂


Leave a comment

gemfile in rails

Gemfile contain all the gems needed for your projects. You can track the available gems and new upcoming gems in rails community at rubygem.org and rubytoolbox.

when, you create a new Rails application it automatically create a Gemfile for you. For other appliaction, like Sinatra you need to run below command on your project

$ bundle init # It will create Gemfile and Gemfile.lock for you

NOTE : before you install any other gem you should must install bundler gem first. If you are using RVM, it is already installed for you in the global gemset i,e you do not need to do anything

There is some syntax for specifying the gems in the gemfile. The complete detail is available here. Iam listing the important one. So my sample Gemfile look like this.

source “http//rubygems.org” # this is the top line. It specify to bundler that gem in this file is to be installed from which repository. You can add multiple repository also , provided it is a valid gem repository. Some of the other repository are  “http//gems.rubyforge.com”, “http//gems.github.com”, infact you can add your personal repository also

source  “http//gems.github.com”# one more source added. avoid adding multiple source unless you are sure that a particular gem is not hosted on “http//rubygems.org” but on that specific repository because if you use multiple source the bundle install command will take more time to execute as the bundler will try to fetch detail from all the mentioned repository before moving to next line. The good thing is that  “http//rubygems.org”contain most of the gem and is enough.
gem "nokogiri" # it is the simplest form of adding a gem to gem file. You can pass various options like version,
require, git, path and group

gem “oauth”, “>= 1.4.2” # it specify that version should be greater or equal to 1.4.2
gem “RedCloth”, “>= 4.1.0”, “< 4.2.0” # version should be between 4.1.0 and 4.2.0
gem "sqlite3-ruby", :require => "sqlite3" # specify that sqlite3 is the main file, which should be used when autorequiring (Bundler.require). the default is the gem name itself i,e if you do not have passed the required function the main file will be sqlite3-ruby

gem “cancan”, :require => false # it prevent bundler from requiring the gem, but still install it and maintain dependencies.

gem ‘jqgrid_for_rails’, :git => "http://github.com/Juanmcuello/jqgrid_for_rails.git" # it specify that the gem should be installed from its git source rather then rubygem.org repository. I find it useful as for jqgrid some new changes are available on git repository of the gem but has not updated on rubygem.org. while using git , you can also pass
other options branch, tag,ref, and submodules You MUST only specify at most one of these options. The default is :branch => “master”. Specify :submodules => true to cause bundler to expand any submodules included in the git repository

gem "my-admin", :path => "vendor/my-admin" # it will install the gem from the specified path. It would will be helpful for your own gem or any gem you have customised for yourself. Unlike :git, bundler does not compile C extensions for gems specified as paths.
gem "weakling", :platforms => :jruby # It specify that this gem should be use only in jruby platforms. There is a no of other platform also available like mri, :mri_18, rbx, mswin, mingw etc gem "ruby-debug", :platforms => [:mri_18, :jruby]

gem “rspec”, :group => :test # will be loaded only in test environment
gem “wirble”, :groups => [:development, :test] # will be loaded in development and test environment

NOTE :

1->The :git, :path, :group, and :platforms options may be applied to a 
group of gems by using block form.

git "git://github.com/rails/rails.git" do
  gem "activesupport"
  gem "actionpack"
end

platforms :ruby do
  gem "ruby-debug"
  gem "sqlite3-ruby"
end

group :development do
  gem "wirble"
  gem "faker"
end

group :development, :test do
  gem "rspec-rails", ">= 2.11.0"
  gem "factory_girl_rails", ">= 3.5.0"
  gem "debugger"
end

2->placing the gems in group do not prohibit there installation i,e irrespective 
of group in which they are placed all gem and its dependency get installed with bundle 
install command. If you want to skip gem in a particular group use bundler command 
line interface (CLI) --without option

bundle install --without test 
bundle install --without development test 

Similarly, bundler provides two run time methods : Bundler.setup and Bundler.require, 
to limit their impact to particular groups.

# setup adds gems to Ruby's load path
Bundler.setup                    # defaults to all groups
require "bundler/setup"          # same as Bundler.setup
Bundler.setup(:default)          # only set up the _default_ group
Bundler.setup(:test)             # only set up the _test_ group (but `not` _default_)
Bundler.setup(:default, :test)   # set up the _default_ and _test_ groups, but no others

#require requires all of the gems in the specified groups
Bundler.require                  # defaults to just the _default_ group
Bundler.require(:default)        # identical
Bundler.require(:default, :test) # requires the _default_ and _test_ groups
Bundler.require(:test)           # requires just the _test_group

3 -> while deploying in production, better run bundle install - -deployment instead of 
     bundle install. see the detail here