by sandipransing
Paypal standard website payment service allows online payment transactions for websites.
Before implementing payments inside rails app needs to have following things in place-
1. Register Paypal sandbox account
2. Paypal Merchant account api credentials i.e. login, password, signature, application_id
3. Paypal Buyer account creds to test payments
Bundle Install
# Gemfile
gem 'activemerchant
Gateway config
# config/gateway.yml
development: &development
mode: test
login: rana_1317365002_biz_api1.gmail.com
password: '1311235050'
signature: ACxcVrB3mFChvPIe8aDWQlLhAPN46oPBQCj7rJWPza6CDZmBURg.
application_id: APP-76y884485P519543T
production:
<<: *development
test:
<<: *development
New Payment Form
= form_for @payment ||= Payment.new, :url => pay_bill_url, :html => {:id => :payForm} do |p|
= p.text_field :amount
= p.submit 'Pay'
Generate & Migrate Payment Model
rails g model payment status:string amount:float transaction_number:string
rake db:migrate
Payment Model
# app/models/payment.rb
class Payment < ActiveRecord::Base
PROCESSING, FAILED, SUCCESS = 1, 2, 3
validates :amount, :presence => true, :numericality => { :greater_than => 0 }
def self.conf
@@gateway_conf ||= YAML.load_file(Rails.root.join('config/gateway.yml').to_s)[Rails.env]
end
## Paypal
def setup_purchase(options)
gateway.setup_purchase(amount * 100, options)
end
def redirect_url_for(token)
gateway.redirect_url_for(token)
end
def purchase(options={})
self.status = PROCESSING
#:ip => request.remote_ip,
#:payer_id => params[:payer_id],
#:token => params[:token]
response = gateway.purchase(amt, options)
if response.success?
self.transaction_num = response.params['transaction_id']
self.status = SUCCESS
else
self.status = FAILED
end
return self
rescue Exception => e
self.status = FAILED
return self
end
private
def gateway
ActiveMerchant::Billing::Base.mode = auth['mode'].to_sym
ActiveMerchant::Billing::PaypalExpressGateway.new(
:login => auth['login'], :password => auth['password'],
:signature => auth['signature'])
end
def auth
self.class.conf
end
end
Billing routes
## Callback URL
match '/billing/paypal/:id/confirm', :to => 'billing#paypal', :as => :confirm_paypal
## Create payment
match '/billing', :to => 'billing#create', :as => :pay_bill
## Request URL
match '/billing/paypal/:id', :to => 'billing#checkout', :as => :billing
match '/billing/thank_you/:id', :to => 'billing#checkout', :as => :billing_thank_you Billing Controller
# app/controllers/billing_controller.rb
class BillingController < ApplicationController
before_filter :get_payment, :only => [:checkout, :paypal, :thank_you]
def create
@payment = Payment.new params[:payment]
if @payment.save
## Paypal Checkout page
redirect_to billing_url
else
render :action => :new
end
end
# ASSUMPTION # payment is valid i.e. amount is entered
def checkout
response = @payment.setup_purchase(:return_url => confirm_paypal_url(@payment), :cancel_return_url => root_url)
redirect_to @payment.redirect_url_for(response.token)
end
## CALL BACK
def paypal
@payment = @payment.purchase(:token => params[:token], :payer_id => params[:PayerID], :ip => request.remote_ip)
@payment.save
redirect_to thank_you_billing_url(@order)
end
private
def get_payment
@payment = Payment.find_by_id(params[:id])
@payment && @payment.valid? || invalid_url
end
end
Views
# app/views/billing/thank_you.html.haml
- if @payment.success?
%p The transaction is successfully completed
- else
%p The transaction failed
Read More…
by sandipransing
Authorize Net SIM gateway transaction skips merchant side creditcard details form and directs transaction to be take place on gateway server.
# Gemfile
gem 'authorize-net'
Register for authorize net sandbox account click herePayment gateway credentials
# config/gateway.yml
development: &development
mode: test
login: 9gdLh6T
key: 67fu45xw6VP92LX1
production:
<<: *development
test:
<<: *development
Generate & Migrate Payment Model
rails g model payment status:string amount:float transaction_number:string
rake db:migrate
SIM gateway methods extracted and added to payment model
# app/models/payment.rb
class Payment < ActiveRecord::Base
PROCESSING, FAILED, SUCCESS = 1, 2, 3
validates :amount, :presence => true, :numericality => { :greater_than => 0 }
def self.conf
@@gateway_conf ||= YAML.load_file(Rails.root.join('config/gateway.yml').to_s)[Rails.env]
end
def success?
self.status == SUCCESS
end
## Authorize :: SIM
def setup_transaction(options ={})
options.merge!(:link_method => AuthorizeNet::SIM::HostedReceiptPage::LinkMethod::POST)
t = AuthorizeNet::SIM::Transaction.new(
auth['login'], auth['key'], amount,
:hosted_payment_form => true,
:test => auth['mode']
)
t.set_hosted_payment_receipt(AuthorizeNet::SIM::HostedReceiptPage.new(options))
return t
end
def auth
self.class.conf
end
end
Payment routes
## Callback URL
match '/billing/:id/confirm', :to => 'billing#authorize', :as => :confirm_billing
## Request URL
match '/billing/:id', :to => 'billing#checkout', :as => :billing
match '/billing/:id/thank_you', :to => 'billing#thank_you', :as => :thank_you_billing
Billing controller
# app/controllers/billing_controller.rb
class BillingController < ApplicationController
helper :authorize_net
before_filter :get_order, :only => [:checkout, :authorize, :thank_you]
def checkout
# ASSUMPTION order is valid means amount is entered
@transaction = @order.setup_transaction(
{:link_text => 'Continue',
:link_url => confirm_billing_url(@order)})
end
## CALL BACK
def authorize
resp = AuthorizeNet::SIM::Response.new(params)
if resp.approved?
@order.status = Payment::SUCCESS
@order.transaction_num = resp.transaction_id
else
@order.status = Payment::FAILED
end
@order.save(:validate => false)
redirect_to thank_you_billing_url(@order)
end
private
def auth
Payment.conf
end
def get_order
@order = Payment.find_by_id(params[:id])
@order && @order.valid? || invalid_url
end
end
Views Forms
# app/views/billing/checkout.html.haml
= form_for :sim_transaction, :url => AuthorizeNet::SIM::Transaction::Gateway::TEST, :html => {:id => :authForm} do |f|
= sim_fields(@transaction)
:javascript
$(document).ready(function(){
$('#authForm').submit();
})
# app/views/billing/thank_you.html.haml
- if @order.success?
%p The transaction is successfully completed
- else
%p The transaction failed
Read More…
by sandipransing
Customizing default rails form builder to adopt for labels, input fields, errors, hints, etc. in order to build forms just in minutes
# app/helpers/app_form_builder.rb
class AppFormBuilder < ActionView::Helpers::FormBuilder
HELPERS = %w[check_box text_field text_area password_field select date_select datetime_select file_field collection_select state_select label calendar_date_select]
def self.create_tagged_field(method_name)
define_method(method_name) do |name, *args|
errs = object.errors.on(name.to_sym) if object && object.errors
# initialize some local variables
if args.last.is_a?(Hash)
label = args.last.delete(:label)
suffix = args.last.delete(:suffix)
klass = args.last.delete(:class)
req = args.last.delete(:required)
end
label = 'none' if method_name == 'hidden_field'
label ||= name.to_s.titleize
label = nil if label == 'none'
klass = klass ? [klass] : []
# Custom class if it exists
if method_name =~ /text_field|check_box|select/
klass << method_name
end
klass << 'f' #A default selector
klass << 'error' if errs.present?
klass = klass.join(' ')
# Required Field Notations
if req == 'all' || (req == 'new' && object.new_record?)
label << @template.content_tag(:span, :*, :class => :req)
end
suffix = @template.content_tag(:label, suffix) if suffix.present?
label = @template.content_tag(:label, label) if label.present?
errs = @template.content_tag(:span, errs.to_s, :class => :message) if errs.present?
reverse = true if method_name == 'check_box'
if reverse
content = "#{super} #{suffix} #{label} #{errs}"
else
content = "#{label} #{super} #{suffix} #{errs}"
end
@template.content_tag(:div, content, :class => klass)
end
end
HELPERS.each do |name|
create_tagged_field(name)
end
end
Read More…
by sandipransing
Authorize Net Payment gateway provides api access to enable online payments
Gateway provides different api options to integrate-
1. Direct Post Method
In this method gateway handles all steps required in payment transaction flow securely and clean manner. To know more on this click here
2. Server Integration Method (SIM)
Here, Payment form and creditcard detail form resides on gateway site and all the steps in transaction carried out at gateway server
3. Advance Integration Method (AIM)
Provides full control of all the transaction steps at merchant server. Payment form resides on merchant side. merchnat server sends authorization and payment capture requests to gateway server where actual transaction takes place and response is sent back to merchant server to notify transaction status. To know detail integration on this click here
Prerequisites before getting started with integration
Sign up for a test account to obtain an API Login ID and Transaction Key. These keys will authenticate requests to the payment gateway.
Read More…
by sandipransing
railroady is UML class diagram generator for rails.
First you need to install `graphviz` pkg in order to have `dot` , `neato` commands available
group :development, :test do
gem railroady
end
Run below command to generate MVC diagrams
bundle install
rake diagram:all
Individual diagram generation
Model Diagram
railroady -M | dot -Tpng > models.png
Controller Diagram
railroady -C | dot -Tpng > controllers.png
AASM Diagram
railroady -A | dot -Tpng > aasm.png
Commands
-M, --models Generate models diagram
-C, --controllers Generate controllers diagram
-A, --aasm Generate "acts as state machine" diagram
Options
# Common options
-b, --brief Generate compact diagram
(no attributes nor methods)
-s, --specify file1[,fileN] Specify given files only for the diagram
(can take a glob pattern)
-e, --exclude file1[,fileN] Exclude given files
(can take a glob pattern)
-i, --inheritance Include inheritance relations
-l, --label Add a label with diagram information
(type, date, migration, version)
-o, --output FILE Write diagram to file FILE
-v, --verbose Enable verbose output
(produce messages to STDOUT)
Models diagram options:
-a, --all Include all models
(not only ActiveRecord::Base derived)
--all-columns Show all columns
(not just content columns)
--hide-magic Hide magic field names
--hide-types Hide attributes type
-j, --join Concentrate edges
-m, --modules Include modules
-p, --plugins-models Include plugins models
-t, --transitive Include transitive associations
(through inheritance)
Controllers diagram options:
--hide-public Hide public methods
--hide-protected Hide protected methods
--hide-private Hide private methods
Other Options
-h, --help Show this message
--version Show version and copyright
Read More…
by sandipransing
We all know Active Support library constantly keeps adding new extensions to ruby core library and hence rails framework.
Do you know now inside ruby class we can have class_attribute placeholder.
class A
class_attribute :counter, :access_time
end
A.counter = 12
A.counter #=> 12
A.new.counter #=> 12
Inheritance
class B < A
end
B.counter #=> 12
B.access_time #=> nil
B.access_time = Time.now
B.access_time #=> Wed Dec 28 18:55:06 +0530 2011
B.new.access_time #=> Wed Dec 28 18:55:06 +0530 2011
A.access_time = nil
Restricting instance from writing class_attributes
class V
class_attribute :counter, :instance_writer => false
end
V.new.counter = 12
NoMethodError: undefined method `counter=' for #
Other ways
a_class = Class.new{class_atrribute :counter}
a_class.counter = 13
a_class.counter #=> 13
a_class.new.counter #=> 13
p = Class.new { class_attribute :help, :instance_writer => false }
p.new.help = 'Got a second!'
NoMethodError: undefined method `help=' for #<#:0x7f8f9d5b1038>
p.help = 'Got a second!'
p.help #=> "Got a second!"
Read More…
by sandipransing
Authorize Net (AIM) method enables internet merchants to accept online payments via credit card.
Below post will show you how to integrate authorize net payment gateway inside rails app to accept online payments using activemerchant library.
# Gemfile
gem 'activemerchant', :require => 'active_merchant'
Register for authorize net sandbox account click here
Payment gateway credentials
# config/authorize_net.yml
development: &development
mode: test
login: 9gdLh6T
key: 67fu45xw6VP92LX1
production:
<<: *development
test:
<<: *development
Payment & creditcard form
# app/views/payments/new
= form_for @payment, :url => payments_url do |f|
= f.text_field :amount
= fields_for :creditcard, @creditcard do |cc|
= cc.text_field :name
= cc.text_field :number
= cc.select :month, Date::ABBR_MONTHNAMES.compact.each_with_index.collect{|m, i| [m, i+1]}, {:prompt => 'Select'}
= cc.select :year, Array.new(15){|i| Date.current.year+i}, {:prompt => 'Select'}
= cc.text_field :verification_value
= f.submit 'Pay'
Payments Controller
# app/controllers/payments_controller.rb
class PaymentsController < ApplicationController
def new
@payment = Payment.new
@creditcard = ActiveMerchant::Billing::CreditCard.new
end
def create
@payment = Payment.new(params[:payment])
@creditcard = ActiveMerchant::Billing::CreditCard.new(params[:creditcard])
@payment.valid_card = @creditcard.valid?
if @payment.valid?
@payment = @payment.process_payment(@creditcard)
if @payment.success?
@payment.save
flash[:notice] = I18n.t('payment.success')
redirect_to payments_url and return
else
flash[:error] = I18n.t('payment.failed')
end
end
render :action => :new
end
end
Generate & Migrate Payment Model
rails g model payment status:string amount:float transaction_number:string
rake db:migrate
Payment Model
# app/models/payment.rb
class Payment < ActiveRecord::Base
PROCESSING, FAILED, SUCCESS = 1, 2, 3
validates :valid_card, :inclusion => {:in => [true], :message => 'Invalid Credit Card'}
validates :amount, :presence => true, :numericality => { :greater_than => 0 }
def process_payment(creditcard)
ActiveMerchant::Billing::Base.mode = auth['mode'].to_sym
self.status = PROCESSING
response = gateway.purchase(amount * 100, creditcard)
if response.success?
self.transaction_number = response.subscription_id
self.status = SUCCESS
else
self.status = FAILED
end
return self
rescue Exception => e
self.status = FAILED
return self
end
def success?
self.status == SUCCESS
end
private
def gateway
ActiveMerchant::Billing::AuthorizeNetGateway.new(
:login => auth['login'],
:password => auth['key'])
end
def auth
@@auth ||= YAML.load_file("#{Rails.root}/config/authorize_net.yml")[Rails.env]
end
end
Read More…
by sandipransing
active_admin is the good way to provide rails administrative interface.
It provides front-end db administration and its customizable too :)
# Gemfile
gem 'activeadmin'
gem 'sass-rails'
gem "meta_search", '>= 1.1.0.pre'
Bundle install, generate config & migrate db
bundle install
rails g active_admin:install
rake db:migrate
Config
# config/initializers/active_admin.rb
ActiveAdmin.setup do |config|
config.site_title = "Web Site :: Admin Panel"
config.site_title_link = "/"
config.default_namespace = :siteadmin
config.authentication_method = :authenticate_admin_user!
config.current_user_method = :current_admin_user
config.logout_link_method = :delete
end
Registering new resource
rails generate active_admin:resource category
Customization
# app/admin/categories.rb
ActiveAdmin.register Category do
scope :published
form do |f|
f.inputs do
f.input :name, :label => 'Name'
f.input :for_type, :label => "Category Type"
end
f.buttons
end
end
Adding Dashboard
ActiveAdmin::Dashboards.build do
section "Recent Categories" do
table_for Category.published.recent.limit(2) do
column :name do |c|
link_to c.name, [:admin, c]
end
column :created_at
end
strong { link_to "View All Categories", admin_categories_path }
end
end
Read More…
by sandipransing
Below extensions to active record base simplifies its usage while coding.
# config/initializers/core_extensions.rb
class ActiveRecord::Base
def self.pagination(options)
paginate :per_page => options[:per_page] || per_page, :page => options[:page]
end
def self.options_for_select(opts={})
opts[:name] ||= :name
opts[:attr] ||= :id
opts[:prompt] ||= 'Please Select'
all.collect{|c| [c.send(opts[:name].to_sym), c.send(opts[:attr].to_sym)]}.insert(0, [opts[:prompt], nil])
end
end
Usage
class Student< ActiveRecord::Base
#attributes #=> name, age
end
##
Student.pagination({:page => 10})
Student.pagination({:per_page => 2, :page => 2})
Student.options_for_select
Student.options_for_select({:prompt => 'Please select'})
Student.options_for_select({:name => :age})
Read More…
by sandipransing
Twitter bootstrap is css toolkit for rapid front-end UI development.
To get will-paginate working with bootstrap css we need to override default pagination link renderer.
Using Bootstrap-sass for rails 3
# Gemfile
gem 'sass-rails'
gem 'bootstrap-sass'
# app/assets/stylesheets/application.css.sass
// Place all the styles related to the home controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
//= require bootstrap
Add WillPaginate LinkRenderer to intitializer
# config/initializers/will_paginate.rb
module WillPaginate
module ActiveRecord
module RelationMethods
alias_method :per, :per_page
alias_method :num_pages, :total_pages
alias_method :total_count, :count
end
end
module ActionView
def will_paginate(collection = nil, options = {})
options[:inner_window] ||= 0
options[:outer_window] ||= 0
options[:class] ||= 'pagination pull-left'
options[:renderer] ||= BootstrapLinkRenderer
super.try :html_safe
end
class BootstrapLinkRenderer < LinkRenderer
protected
def html_container(html)
tag :div, tag(:ul, html), container_attributes
end
def page_number(page)
tag :li, link(page, page, :rel => rel_value(page)), :class => ('active' if page == current_page)
end
def previous_or_next_page(page, text, classname)
tag :li, link(text, page || 'javascript:void(0)'), :class => [classname[0..3], classname, ('disabled' unless page)].join(' ')
end
def gap
tag :li, link(super, 'javascript:void(0)'), :class => 'disabled'
end
end
end
end
Read More…
by sandipransing
Scopes are partial query conditions to database queries. scopes are always prefixed to class finders. There are several ways to use scopes inside rails models.
# 1. Scope defined below gets loaded while class definition loads
scope :active, where(:active => true)
scope :archived, where(:archived => true, :post_type => :general)
# 2.Dynamic scopes needs to be always defined inside lambda
scope :not_expired, lambda { where('expiry_date <= ?', Date.today) }
# 3.Combining scopes
scope :visible, published.not_expired
# 4. Passing parameters to scopes
# avoid below
scope :created_by_user, lambda {|user|
where('user_id = ?', user)
}
# use this
scope :created_by_user, lambda {|user|
where(:user_id => user)
}
# 5. passing multiple parameters
# avoid below
scope :made_between, lambda{|from, to|
where('created_date >= ? and created_date <= ?', from, to)
}
# use this
scope :made_between, lambda{|from, to|
where('created_date >= :from and created_date <= :to', :from => from, :to => to)
}
# 6. associations inside scope (joins and includes)
# below will perform eager loading effective when rendering posts with comments
scope :with_user_comments, lambda{|user|
includes(:comments).where('comments.user_id = ?', user)
}
# faster
# also can be done as post.comments.where(:user_id => user)
scope :with_user_comments, lambda{|user|
joins(:comments).where('comments.user_id = ?', user)
}
So, at last would suggest making use of symbols when there are multiple parameters to scopes and make maximum use of scopes rather than having where conditions everywhere :)
Read More…
by sandipransing
Ruby language is dynamic and robust. We can define methods inside ruby classes at runtime.
# bash
class A
define_method :a do
puts "hello"
end
define_method :greeting do |message|
puts message
end
end
A.new.a #=> hello
A.new.greeting 'Ram ram' #=> Ram ram
Can you imagine using dynamic methods below 24 lines of code is optimized to just 8 lines
To know more on below code read
# Earlier code
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_staff, :current_employee, current_admin
def authenticate_staff!(opts={})
current_staff || not_authorized
end
def current_staff
current_user if current_user.is_a? Staff
end
def authenticate_employee!(opts={})
current_employee || not_authorized
end
def current_employee
current_user if current_user.is_a? Employee
end
def authenticate_admin!(opts={})
current_admin || not_authorized
end
def current_admin
current_user if current_user.is_a? Admin
end
end
# New Version using dynamic methods
%w(Staff Employee Admin).each do |k|
define_method "current_#{k.underscore}" do
current_user if current_user.is_a?(k.constantize)
end
define_method "authenticate_#{k.underscore}!" do |opts={}|
send("current_#{k.underscore}") || not_authorized
end
end
Read More…
by sandipransing
jQuery datepicker plugin is used to display inline calendar popup that eases user input experience while entering date/time fields. Calendar can be easily binded to any html DOM element. To Apply different styles download css from here
# Gemfile
gem "jquery-rails"
# console
bundle install
# app/assets/javascripts/application.js.coffee
//= require jquery
//= require jquery_ujs
//= require jquery-ui
# app/views/layouts/application.html.haml
= stylesheet_link_tag "application"
= stylesheet_link_tag "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css"
= javascript_include_tag "application"
Before using timepicker download jquery-ui-timepicker js
wget http://trentrichardson.com/examples/timepicker/js/jquery-ui-timepicker-addon.js app/assets/javascripts/
Add timepcker js to application.js.coffee
//= require jquery-ui-timepicker-addon
## inside views
# app/views/users/_form.html.haml
= form_for @user ||= User.new do |f|
= f.text_field :birth_date, :id => 'birthDate'
= f.text_field :birth_time, :id => 'birthTime'
= f.text_field :exam_on, :id => 'examOn'
:javascript
$(document).ready(function() {
$("#birthDate").datepicker();
$("#birthTime").timepicker();
$("#examOn").datetimepicker();
$('#ui-datepicker-div').removeClass('ui-helper-hidden-accessible')
# customizations
$('#birth_date').datepicker({ dateFormat: 'dd-mm-yy' });
$('#birth_date').datepicker({ disabled: true });
$("#examOn").datetimepicker({ ampm: true });
$("#examOn").datetimepicker({ timeFormat: 'h:m', separator: ' @ ' });
Read More…
by sandipransing
Heroku is readonly file system hence write operations can only be done inside tmp directory.
Asset compilation on heroku can be handled in different ways
#1. compiling locally and placing inside assets directory
RAILS_ENV=production bundle exec rake assets:precompile
#2. It compiles assets while slug compiles
#3. Run time asset compilation
# It compiles assets for every rails request if it notifies assets got modified
# config/application.rb
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
config.assets.prefix = Rails.root.join('tmp/assets').to_s
# config/environments/production.rb
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = true
Note: write operation made inside tmp directory can not make any guarantee of being persisted hence be careful while using.
Read More…
by sandipransing
Devise handles authentication, authorization part inside rails application quite easily and its customizable too. One can always customize default devise configurations.
This Post will show how to manage multiple resources (like admin, staff, employees, guests etc.) through devise and STI with individual registrations process but login section will be the same for all.
# Gemfile
gem 'devise'
# console
bundle install
rails g devise_install
rails g devise User
rake db:migrate
rake routes
# User model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :lockable, :timeoutable, :confirmable and :activatable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation
end
## Single Table Inheritance
# Admin model
class Admin < User
end
# Staff
class Staff < User
end
# Employee
class Employee < User
end
# Guest
class Guest < User
end
# routes
devise_for :users, :skip => :registrations
devise_for :admins, :skip => :sessions
devise_for :staffs, :skip => :sessions
devise_for :employees, :skip => :sessions
devise_for :guests, :skip => :sessions
# customizing default login/logout routes, views, actions
devise_for :users, :controller => {:sessions => 'sessions'}, :skip => [:sessions, :registrations] do
delete '/logout', :to => 'sessions#destroy', :as => :destroy_user_session
get '/login', :to => 'sessions#new', :as => :new_user_session
post '/login', :to => 'sessions#create', :as => :user_session
end
# app/controllers/sessions_controller
class SessionsController < Devise::SessionsController
end
## overriding default after sign in path
# app/controller/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :account_url
def account_url
return new_user_session_url unless user_signed_in?
case current_user.class.name
when 'Customer'
edit_customer_registration_url
when 'Admin'
edit_home_page_section_url
else
root_url
end if user_signed_in?
end
end
# app/controllers/sessions_controller.rb
class SessionsController < Devise::SessionsController
def after_sign_in_path_for(resource)
stored_location_for(resource) || account_url
end
end
## Changing default login field email to username
# config/initializers/devise.rb
config.authentication_keys = [ :username ]
# app/models/user.rb
validates :username, :presence => true,
:uniqueness => {:allow_blank => true},
:format => {:with => /^\w+[\w\s:?']+$/i, :allow_blank => true}
def email_required?
false
end
Adding devise authentication and authorization helper methods for above resources.
read more here
Read More…
by sandipransing
Install RVM first
bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvminstaller)
rvm list known
# MRI Rubies
[ruby-]1.8.6-head
[ruby-]1.8.7[-p352]
[ruby-]1.9.3-head
ruby-head
# JRuby
jruby-1.2.0
jruby-head
# Rubinius
rbx-1.0.1
rbx-2.0.0pre
# Ruby Enterprise Edition
ree-1.8.6
ree-1.8.7-head
Install ruby 1.9.3
rvm install 1.9.3-head
rvm gemset create rails311
rvm use 1.9.3-head@rails311 --default
gem install rails -v3.1.1 --no-rdoc --no-ri
gem install heroku
gem install rb-readline
Create new rails project
rails new cdc -m http://railswizard.org/b22092a4358bbebb3a46.rb -J -T
Heroku Deployment Done
http://railsblank.heroku.com/ (production)
Local System nginx-passenger setup
gem install passenger
rvmsudo passenger-install-nginx-module
If you find pcre download error then make sure you libpcre-dev pkg
installed on your system otherwise install it and re-run
sudo apt-get install libpcre3-dev
Nginx Configuration
http {
passenger_root /home/sandip/.rvm/gems/ruby-1.9.3-head@rails311/gems/passenger-3.0.9;
passenger_ruby /home/sandip/.rvm/wrappers/ruby-1.9.3-head@rails311/ruby;
server {
listen 80;
server_name railsblank.local;
root /home/sandip/railsblank/public;
rails_env development;
passenger_enabled on;
}
git source code
git clone git://github.com/sandipransing/rails_blank.git
Read More…
by sandipransing
Stepwise guide to configure paperclip default options,
setting up aws-s3 storage in rails
Inside Gemfile
gem 'aws-s3', :require => 'aws/s3'
gem 'paperclip'
bundle install
Generate Print model to hold image
rails g model print image_file_name:string image_content_type:string image_file_size:string
rake db:migrate
Add s3 credentials to YML file
# config/s3.yml
access_key_id: DASDFG7KACNxIJdJXHPQ
secret_access_key: BnDrTnzCTX+R707wYEP/aCEqAsDFG7sgW
Add default paperclip attachment options to initializer
# Make sure to add host url inside config/environments
# HOSTNAME = 'http://lordganesha.com'
Paperclip::Attachment.default_options.merge!(
:storage => 's3',
:s3_credentials => YAML.load_file("#{Rails.root}/config/s3.yml"),
:path => ":class/:attachment/#{Rails.env}/:id/:style/:basename.:extension",
:default_url => "http://#{HOSTNAME}/images/paperclip/:class/:attachment/default.jpg",
:bucket => 'ganesha'
)
Add image attachment code to print model
# app/models/print.rb
class Print < ActiveRecord::Base
has_attached_file :image,
:styles => {:medium => ["400x400#", :jpg],
:thumb => ["100x100#", :jpg],
:slider => ["300x300#", :jpg]}
#validates_attachment_presence :image
validates_attachment_size :image, :less_than => 1.megabytes, :message => 'file size maximum 1 MB allowed'
validates_attachment_content_type :image, :content_type => ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/pjpeg', 'image/x-png']
end
Inside views
# inside new.html.haml
= form_for @print do
f.file_field :image
Read More…
by sandipransing
Upload image via paperclip via passing URL instead of file upload
# Consider Print instance with image as file attachment
class Print < ActiveRecord::Base
has_attached_file :image
def upload_image(url)
begin
io = open(URI.escape(url))
if io
def io.original_filename; base_uri.path.split('/').last; end
io.original_filename.blank? ? nil : io
p.image = io
end
p.save(false)
rescue Exception => e
logger.info "EXCEPTION# #{e.message}"
end
end
end
Text code from console
p = Print.new
url = "http://ocdevel.com/sites/ocdevel.com/files/images/rails.png"
p.upload_image(url)
Read More…
by sandipransing
While developing rails application we often come across situation where you wanted different rails models connecting different tables of different databases.
Example: We are having ndnc model holding ndnc records associated with database ndnc.
Lets create ConnectionBase model that will connect to other databse 'ndnc' and that will be extended from ActiveRecordBase and put that inside library files
vi lib/connection_base.rb
class ConnectionBase < ActiveRecord::Base
establish_connection(
:adapter => "postgresql",
:username=> "sandip",
:password => "2121",
:database => "ndnc"
)
end
Wherever you wanted to connect to other database i.e. ndnc you can extend that particular model with ConnectionBase
class Ndnc < ConnectionBase
# connects to ndnc table of ndnc database
end
Please make sure library files are loaded while server startup
# vi config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
Done !
In cases where you want only one particular model connecting other database table, you can put connection setting itself in that model.
Read More…
by sandipransing
Hiding Whole page content and displaying only particular div using css
<style media="print" type="text/css">
@media print
{
body * { visibility: hidden; }
#PrintDiv * { visibility: visible; }
#PrintDiv { position: absolute; top: 40px; left: 30px; }
}
</style>
Read More…
by sandipransing
Migrating from svn to git
1. Install git-svn
sudo apt-get install git-svn
2. Clone svn repositoy
git svn clone -s svn://server/project_myt/trunk proj
To add svn users and git users mapping
Create author-file
#vi authorsfile
sandip = sandipransing
amit = amitk
root = sandipransing
git svn --author-file=authorfile clone -s svn://server/project_myt/trunk proj
3. Add git repository url
cd proj
git remote add git@github.com:USERNAME/project.git
4. Push repository to git
git push origin master
To do svn pull for latest changes
git svn rebase
Read More…
by sandipransing
In order to get tata photon working on ubuntu machine you need to install following packages
1. usb-modeswitch-data
2. usb-modeswitch
Either you can download them from ubuntu site and install locally or install using apt manager
Download links
http://packages.debian.org/squeeze/usb-modeswitch-data
http://packages.debian.org/squeeze/usb-modeswitch
apt installation
sudo apt-get install usb-modeswitch-data usb-modeswitch usb-modeswitch
After successful installation,
1. Connect photon usb card
2. Execute following commands one after another.
sudo usb_modeswitch -c /etc/usb_modeswitch.d/12d1\:1446
wvdial
...and you should get connected via photon!
Read More…
by sandipransing
Create new rails project
rails new demo -d mysql
Add active_scaffold gem to bundler
gem "active_scaffold_vho"
Run bundle install command
bundle install
Setup active scaffold to use jQuery
rails g active_scaffold_setup jquery
create public/javascripts/rails_jquery.js
create public/javascripts/jquery-ui-timepicker-addon.js
create config/initializers/active_scaffold.rb
insert app/views/layouts/application.html.erb
insert config/locales/en.yml
gsub app/views/layouts/application.html.erb
Generate active scaffold for resource city & zone
rails g active_scaffold City name:string
invoke active_record
create db/migrate/20110408123206_create_cities.rb
create app/models/city.rb
invoke test_unit
create test/unit/city_test.rb
create test/fixtures/cities.yml
route resources :cities do as_routes end
invoke active_scaffold_controller
create app/controllers/cities_controller.rb
create app/helpers/cities_helper.rb
invoke test_unit
create test/functional/cities_controller_test.rb
create app/views/cities
rails g active_scaffold Zone name:string city:references
invoke active_record
create db/migrate/20110408123531_create_zones.rb
create app/models/zone.rb
invoke test_unit
create test/unit/zone_test.rb
create test/fixtures/zones.yml
route resources :zones do as_routes end
invoke active_scaffold_controller
create app/controllers/zones_controller.rb
create app/helpers/zones_helper.rb
invoke test_unit
create test/functional/zones_controller_test.rb
create app/views/zones
Add Associations
class City < ActiveRecord::Base
end
class Zone < ActiveRecord::Base
belongs_to :city
end
class City < ActiveRecord::Base
has_many :zones
end
Migrate database
rake db:create
rake db:migrate
== CreateCities: migrating ===================================
-- create_table(:cities)
-> 0.1411s
== CreateCities: migrated (0.1413s) ==========================
== CreateZones: migrating ====================================
-- create_table(:zones)
-> 0.1507s
== CreateZones: migrated (0.1510s) ===========================
Start Server
rails s
Visit Browser URL: http://localhost:3000/cities
Snap
Read More…
by sandipransing
Edit nginx configuration and look for html block.
Inside html block add following line.
http {
include conf/mime.types;
default_type application/octet-stream;
client_max_body_size 10m;
....
}
In above configuration "application/octet-stream" supports any kind of file upload.
Read More…
by sandipransing
Twitter share and facebook like button for html/erb
<div class='spread'>
<div class='twshare left'>
<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="funonrails">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
</div>
<script src="http://connect.facebook.net/en_US/all.js#xfbml=1"></script><fb:like href="" layout="button_count" show_faces="false" width="450" font=""></fb:like>
</div>
Twitter share and facebook like button for haml
.spread
.twshare.left
%a.twitter-share-button.left{"data-count" => "horizontal", "data-via" => "fuonrails", :href => "http://twitter.com/share"} Tweet
%script{:src => "http://platform.twitter.com/widgets.js", :type => "text/javascript"}
.fshare.left{:style => 'padding-left: 0px; margin-left: 10px;'}
%script{:src => "http://connect.facebook.net/en_US/all.js#xfbml=1"}
%fb:like{:layout => "button_count", :show_faces => "false", :width => "450"}
.CLR
Sample Buttons
Read More…
by sandipransing
rails has built in number_to_currency helper which takes options like unit, delimeter, seperator which displays foreign currency correctly but somehow it is not best suited for indian currency.
Below is how we managed 2 years ago to display indian currency formatted properly with comma as seperator. personally i think it could be more better than what it is currently ;)
Number to indian currency(rupees) helper
module ApplicationHelper
def number_to_indian_currency(number)
if number
string = number.to_s.split('.')
number = string[0].gsub(/(\d+)(\d{3})$/){ p = $2;"#{$1.reverse.gsub(/(\d{2})/,'\1,').reverse},#{p}"}
number = number.gsub(/^,/, '') + '.' + string[1] if string[1]
# remove leading comma
number = number[1..-1] if number[0] == 44
end
"Rs.#{number}"
end
Sample Output for different combinations
>> helper.number_to_indian_currency(2000)
=> "Rs.2,000"
>> helper.number_to_indian_currency(2040)
=> "Rs.2,040"
>> helper.number_to_indian_currency(2040.50)
=> "Rs.2,040.5"
>> helper.number_to_indian_currency(2040.54)
=> "Rs.2,040.54"
>> helper.number_to_indian_currency(1222040.54)
=> "Rs.12,22,040.54"
After doing google today found from Piyush Ranjan's Blog that yes there are ways to optimize code.
Optimized Version
module ApplicationHelper
def number_to_indian_currency(number)
"Rs.#{number.to_s.gsub(/(\d+?)(?=(\d\d)+(\d)(?!\d))(\.\d+)?/, "\\1,")}"
end
end
Waw one line of code, Look at the beauty of regular expression :) Truely amazing !
Integrating Webrupee symbol
First include follwing stylesheet in your layout
//public/stylesheets/font.css
@font-face {
font-family: "WebRupee";
font-style: normal;
font-weight: normal;
src: local("WebRupee"), url("http://cdn.webrupee.com/WebRupee.V2.0.ttf") format("truetype"), url("http://cdn.webrupee.com/WebRupee.V2.0.woff") format("woff"), url("http://cdn.webrupee.com/WebRupee.V2.0.svg") format("svg");
}
.WebRupee {
font-family: 'WebRupee';
}
Improved Version of Helper
module ApplicationHelper
def number_to_indian_currency(number, html=true)
txt = html ? content_tag(:span, 'Rs.', :class => :WebRupee) : 'Rs.'
"#{txt} #{number.to_s.gsub(/(\d+?)(?=(\d\d)+(\d)(?!\d))(\.\d+)?/, "\\1,")}"
end
end
Usage
>> helper.number_to_indian_currency(400)
=> "<span class="WebRupee">Rs.</span> 400"
>> helper.number_to_indian_currency(5921, false)
=> "Rs. 5,921"
>> helper.number_to_indian_currency(9921)
=> "<span class="WebRupee">Rs.</span> 9,921"
This will show you rupees symbol on your webpages.
Read More…
by sandipransing
While looking for accessing rails template tags to be accessed on rails console in order to examine whatever written needs to be correct, found that - rails template tags can be tested on rails console using helper object
module ApplicationHelper
def display_amount(amount)
number_to_currency amount, :precision => 0
end
end
Helpers on rails console
rails c
>> helper.text_field_tag :name, 'sandip'
=> "<input id="name" name="name" type="text" value="sandip" />"
>> helper.link_to 'my blog', 'http://funonrails.com'
=> "<a href=''http://funonrails.com>my blog</a>"
>> helper.display_amount(2000)
=> "$2,000"
isn't cool ? though it's not finished yet. we can include helper files on console and access custom helper methods too
>> include ActionView::Helpers
=> Object
>> include ApplicationHelper
=> Object
>> include ActionView::Helpers::ApplicationHelper^C
>> display_amount 2500
=> "$2,500"
Using same way one can make use helpers in rake tasks file. Make sure environment is getting loaded into rake task.
# lib/tasks/helper_task.rake
namespace :helper do
desc 'Access helper methods in rake tasks'
task :test => :environment do
include ActionView::Helpers
include ApplicationHelper
puts display_amount 2500 #=> "$2,500"
end
end
Accessing helpers in Action Mailers
class Notifier < ActionMailer::Base
add_template_helper(ApplicationHelper)
def greet(user)
subject "Hello #{user.name}"
from 'no-reply@example.com'
recipients user.email
sent_on Time.now
@user = user
end
# app/views/notifier/greet.html.erb
Hi <%= @user.try(:name)%>,
Greetings !!!
You have got <%= display_amount(3000) %>
Rails routes on rails console
rails c
>> app.root_url
=> "http://www.example.com/"
>> app.change_password_path
=> "/change/password"
>> app.change_password_url
=> "http://www.example.com/change/password"
Now you may have got requirement to access routes inside rake tasks. Here is the way to do that-
# lib/tasks/route_test.rake
namespace :routes do
desc 'Access helper methods in rake tasks'
task :test => :environment do
include ActionController::UrlWriter
default_url_options[:host] = "myroutes.check"
puts root_url #=> "http://myroutes.check"
end
end
Optionally you can set value of host parameter from action mailer host configuration using
default_url_options[:host] = ActionMailer::Base.default_url_options[:hos]
Attention: This is my preferred way to use helpers and routes when needed and there may have other choices to do same. Anyone having better approach please feel free to add your valuable comment. I will definitely incorporate that in further developments.
Got Easy, Cheers ;)
Read More…
by sandipransing
Delayed Job & Monit configuration
We were struggling through how to monit delayed_job from past few months because monit doesn't work seamlessly with delayed_job start/stop commands and finally we got able to monit delayed_job.
Here is our old configuration that wasn't working anyhow-
check process delayed_job with pidfile /home/sandip/shared/pids/delayed_job.pid
stop program = "/bin/bash -c 'cd /home/sandip/current && RAILS_ENV=production script/delayed_job stop'"
start program = "/bin/bash -c 'cd /home/sandip/current && RAILS_ENV=production script/delayed_job start'"
if totalmem > 100.0 MB for 3 cycles then restart
if cpu usage > 95% for 3 cycles then restart
After doing google & looking at stackoverflow, we found different solutions to work with but none of them found useful to me. :(
After reading google group someone (not remembering exactly) directed to write a init script for delayed_job server and that perfectly worked for me and my headache of self moniting delayed_job ended up ;)
Here is delayed_job init script
## /etc/init.d/delayed_job
#! /bin/sh
set_path="cd /home/sandip/current"
case "$1" in
start)
echo -n "Starting delayed_job: "
su - root -c "$set_path; RAILS_ENV=production script/delayed_job start" >> /var/log/delayed_job.log 2>&1
echo "done."
;;
stop)
echo -n "Stopping delayed_job: "
su - root -c "$set_path; RAILS_ENV=production script/delayed_job stop" >> /var/log/delayed_job.log 2>&1
echo "done."
;;
*)
echo "Usage: $N {start|stop}" >&2
exit 1
;;
esac
exit 0
finally here is the working monit delayed_job configuration
check process delayed_job with pidfile /home/sandip/shared/pids/delayed_job.pid
stop program = "/etc/init.d/delayed_job stop"
start program = "/etc/init.d/delayed_job start"
if totalmem > 100.0 MB for 3 cycles then restart
if cpu usage > 95% for 3 cycles then restart
Thinking Sphinx monit configuration
check process sphinx with pidfile /home/sandip/shared/pids/searchd.pid
stop program = "/bin/bash -c 'cd /home/sandip/current && /usr/bin/rake RAILS_ENV=production ts:stop'"
start program = "/bin/bash -c 'cd /home/sandip/current && /usr/bin/rake RAILS_ENV=production ts:start'"
if totalmem > 85.0 MB for 3 cycles then restart
if cpu usage > 95% for 3 cycles then restart
Adhearsion (ahn) monit confiuration
check process ahn with pidfile /home/josh/shared/pids/ahnctl.pid
stop program = "/bin/bash -c 'cd /home/sandip/current && /usr/bin/ahnctl stop adhearsion'"
start program = "/bin/bash -c 'cd /home/sandip/current && /usr/bin/ahnctl start adhearsion'"
if totalmem > 100.0 MB for 3 cycles then restart
if cpu usage > 95% for 3 cycles then restart
Nginx monit configuration
check process nginx with pidfile /opt/nginx/logs/nginx.pid
start program = "/opt/nginx/sbin/nginx"
stop program = "/opt/nginx/sbin/nginx -s stop"
if cpu is greater than 70% for 3 cycles then alert
if cpu > 80% for 5 cycles then restart
if 10 restarts within 10 cycles then timeout
Read More…
by sandipransing
Rails 3 Installation
sudo gem install rails -v3.0.4
postgres as db installation<>br/
$ sudo apt-get install postgresql
Rails 3 App with postgres as database
$ rails new pg -d postgres
bundle installation
It will install dependency gems & postgres adapter for db connection
bundle install
Here by default 'postgres' database user gets created while installation but i recommend to create new db user with name same as of system user owning project directory permissions.
User owning file permission can be found using
ls -l pg
drwxr-xr-x 7 sandip sandip 4096 2011-02-23 15:38 app
drwxr-xr-x 5 sandip sandip 4096 2011-02-23 18:14 config
-rw-r--r-- 1 sandip sandip 152 2011-02-23 15:38 config.ru
...
Default 'postgres' database user gets created while installation
## Snap of database.yml
development:
adapter: postgresql
encoding: unicode
database: pg_development
username: sandip
pool: 5
Create new database user
pg $ sudo su postgres
pg $ createuser sandip
Shall the new role be a superuser? (y/n) y
pg $ exit
exit
Create a first development database:
pg $ psql template1
Welcome to psql 8.4.6, the PostgreSQL interactive terminal.
...
template1=# \l
List of databases
Name | Owner | Encoding
-----------+----------+----------
postgres | postgres | UTF8
template0 | postgres | UTF8
template1 | postgres | UTF8
(3 rows)
template1=# CREATE DATABASE pg_development;
CREATE DATABASE
template1=# \l
List of databases
Name | Owner | Encoding
-------------------+----------+----------
postgres | postgres | UTF8
pg_development | sandip | UTF8
template0 | postgres | UTF8
template1 | postgres | UTF8
(4 rows)
template1=# \q
Start rails server
pg $ rails s
Getting hands on postgres terminal
1. Login onto terminal
psql -U DB_USERNAME -d DB_NAME -W DB_PASSWORD
2. List databases
\l
3. Display tables
\dt
4. Exit from terminal
\q
Read More…
by sandipransing
While working on remote machine we often get headache of entering password for ssh login, scp files from one server to another server. Adding public key as authorized_keys on remote server solves this problem.
Copying from my system to remote server
cat ~/.ssh/id_rsa.pub | ssh sandip@server 'cat >> ~/.ssh/authorized_keys'
Copying from remote server to my system
ssh server 'cat ~/.ssh/id_rsa.pub' | cat >> ~/.ssh/id_rsa_client.pub
Read More…
by sandipransing
# in config/environment.rb
config.gem 'hoptoad_notifier'
# from your Rails root:
$ rake gems:install
$ rake gems:unpack GEM=hoptoad_notifier
$ script/generate hoptoad --api-key your_key_here
Read More…
by sandipransing
Basic commands to open/Edit crontab file
Editing crontab file
crontab -e
Displaying crontab file
crontab -l
Remove crontab
crontab -r
crontab syntax
cron command basically takes 6 input parameters of which each input can take multiple arguments
for that one can make use of comma or pipe separator
# min hour dom mon dow command
* * * * * (command)
Here * means for every. Above command will get executed for every minute
Detailed syntax
* * * * * command to be executed
- - - - -
| | | | |
| | | | +----- day of week (0 - 6) (Sunday=0)
| | | +------- month (1 - 12)
| | +--------- day of month (1 - 31)
| +---------- hour (0 - 23)
+------- min (0 - 59)
Example commands
# Generate progressive report for every active user at 11:45 p.m.
45 23 * * * (cd /home/sandip/current/; rake ace:daily_progressive_report RAILS_ENV=production)
# Take database backup every night
59 2 * * * (cd /home/sandip/current/; rake db:backup RAILS_ENV=production)
# Initialize grouping on database every sunday
29 3 * * 0 (cd /home/sandip/current/; rake ace:initializeCarGrouping RAILS_ENV=production)
# Generate daily stats on 4:30 AM & 12:30 PM and 4:30 PM
30 4,12,16 * * * (cd /home/sandip/current/; rake ace:daily_call_statistics RAILS_ENV=production)
# Rotate sphinx indexes updated evry hour if missed out somehow
0 * * * * (cd /user/local/bin/; indexer --rotate --config /home/sandip/current/config/production.sphinx.conf)
Read More…
by sandipransing
Testing restful & polymorphic resource routes on rails console
Open rails console
rails c # In rails 3
OR
ruby script/console
app object of URL
>> app
=> #<ActionController::Integration::Session:0xc164fac @result=nil, @status=nil, @accept="text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", @path=nil, @request_count=0, @application=#<ActionController::Dispatcher:0xc1644f8 @output=#<IO:0x85e34ec>>, @remote_addr="127.0.0.1", @host="www.example.com", @controller=nil, @https=false, @request=nil, @headers=nil, @cookies={}, @status_message=nil, @named_routes_configured=true, @response=nil>
Root URL
>> app.root_url => "http://www.example.com/"
Plural paths
>> app.calls_path => "/calls"
Singular routes
>> app.audio_call_path ActionController::RoutingError: audio_call_url failed
>> app.audio_call_path(1) => "/calls/1/audio"
>> app.audio_call_path(13) => "/calls/13/audio"
>> app.audio_call_path(13, :name => 'san') => "/calls/13/audio?name=san"
Polymorphic URLS
app.polymorphic_path(Call.first, :action => 'audio') => "/calls/253/audio"
>> app.polymorphic_path(Call.new) => "/calls"
Read More…
|