Thursday, October 25, 2012

Dynamic conditions to rails associations

by sandipransing 0 comments
We all know that rails models associations gets defined while class definitions are loaded and once defined can't be changed. But still you can make use of block parameter to conditions to have dynamic query conditions inside associations.

Below line explains how to define dynamic associations -

has_one :code_sequence, :class_name => 'Sequence', :conditions => 'kind = "#{self.kind}"'

Please make a note that below code won't be working -
has_one :code_sequence, :class_name => 'Sequence', :conditions => proc { |c| ['kind = ?', c.kind] }
Read More…

Wednesday, April 4, 2012

Upgrading from Rails 2.1.x to Rails 2.3.11

by sandipransing 0 comments
If your application is currently on any version of Rails 2.1.x, The following changes needs to be done for upgrading your application to Rails 2.3.11

1. First install Rails version 2.3.11

gem install rails -v2.3.11


2. Freeze app ruby gems

rake rails:freeze:gems

Hopefully it should work for you but it gave me following error

undefined method `manage_gems' for Gem:Module


3. Create sample rails 2.3.11 app

rails _2.3.11_ testsapp


Now, Copy all missing "config/initializers/*" files from new "testapp to the application that to be upgraded.

cp testapp/config/initializers/* config/initializers


4. Change Rails version inside environment.rb to Rails 2.3.11

# Specifies gem version of Rails to use when vendor/rails is not present
RAILS_GEM_VERSION = '2.3.11'


5. Rename app/controllers/application.rb file to app/controllers/application_controller.rb

OR


rails:update:application_controller


6. Start rails server and fix the issues one by one.

ruby script/server
Read More…

Thursday, February 23, 2012

ruby enumerable & to_proc (ampersond & symbol shortcut)

by sandipransing 0 comments
Basically Enumerable mixin gives collection classes a variety of traverse, search, sort methods.
understanding ruby blocks i.e. proc
blocks are statements of code written in ruby. one can take them as similar to c language macro's
Different ways to define blocks
a = proc do puts "hello" end a.call #=> hello b = lambda do |u| puts "hello #{u}" end b.call('sandip')#=> hello sandip c = proc {|user| puts user } c.call('sandip') #=> sandip Passing block to enumerator
Lets assume we have collection array of strings and we want to print it
a = ['hi', 'sandip', 'how', 'you', 'doing', '?'] => ["hi", "sandip", "how", "you", "doing", "?"] a.each {|w| puts w } q = proc {|w| puts w } => # a.each(&q) #=> hi sandip how you doing ? a.map{|r| q.call(r)} #=> hi sandip how you doing ? Understanding symbol#to_proc
Symbol has method to_proc which converts symbol to block where symbol is taken as method to be executed on first argument of proc
How to_proc got implemented inside Symbol class class Symbol def to_proc Proc.new { |*args| args.shift.__send__(self, *args) } end end Lets have some examples
v = :even?.to_proc # equivalent to proc {|a| a.even?} #=> # q = [1, 2, 3, 5, 67] q.map(&v) => [false, true, false, false, false] Is there any shortcut?
Yes, there is shortcut to have block passed to enumerators on the fly using ampersand followed by colon (i.e. symbol)
q = [1, 2, 3, 5, 67] q.map(&:even?) <=> q.map(&:even?.to_proc) q.map(&:even?.to_proc) #=> [false, true, false, false, false] q.map(&:even?) #=> [false, true, false, false, false] Some handy examples
[1, 2, 3, 5, 67].inject(&:+) #=> 78 [1, 2, 3, 5, 67].inject(:+) #=> 78 [1, 2, 3, 5, 67].any?(&:even?) #=> true [1, 2, 3, 5, 67].detect(&:even?) #=> 2 ['ruby', 'on', 'rails'].map(&:upcase) #=> ["RUBY", "ON", "RAILS"]
Read More…

Tuesday, January 31, 2012

dynamic & bounded parameters and named routes

by sandipransing 0 comments
Rails routes can be customized as your own routes with parameters but first you should understand how routes behaves.
Adding dynamic parameters to routes
Here exact parameters are matched to route and presence of each parameter is mandatory in order to construct urls. blank parameter will raise RoutingError exception.
Exact matched named route declared as - match ':a/:b/:c', :to => 'home#index', :as => :q now go to the rails console - ruby-1.9.3-head :005 > app.q_url(:a, :b, :c) => "http://www.example.com/a/b/c" ruby-1.9.3-head :006 > app.q_url(:a, :b, '') ActionController::RoutingError: No route matches {:controller=>"home", :a=>:a, :b=>:b, :c=>""} Bound parameters to named routes
If you are too sure that certain parameter can be blank then you can define it as optional parameter inside route -
match ':a/:b(/:c)', :to => 'home#index', :as => :q rails console ruby-1.9.3-head :010 > app.q_url(:a, :b, '') => "http://www.example.com/a/b?c=" ruby-1.9.3-head :011 > app.q_url(:a, :b) => "http://www.example.com/a/b"
Read More…

puts, to_s and inspect on ruby object

by sandipransing 0 comments
`puts` converts ruby object into string by invoking to_s method on object. The default to_s prints the object's class and an encoding of the object id. In order to print human readable form of object use inspect
locs = Location.find_by_sql('select * from locations') Location Load (0.5ms) select * from locations Puts Object internally invokes to_s method on object to print locs.each do |l| # it calls to_s method on object puts l end #<Location:0x000000055bb328> #<Location:0x000000055bb058>
puts object followed by subsequent invoke of inspect method outputs readable object locs.each do |l| puts l.inspect # prints actual object end #<Location id: 15, name: "Annettaside3", street: "71838 Ritchie Cape", city: "East Destanystad", state: "Utah", zip: "58054", phone: 123456, other_phone: 987654, staff_strength: 40, is_active: true, created_at: "2012-01-25 11:17:26", updated_at: "2012-01-25 11:17:26", country_name: "Korea"> #<Location id: 16, name: "Sporerbury4", street: "73057 Jerad Shoal", city: "South Kyliefurt", state: "Delaware", zip: "46553-3376", phone: 123456, other_phone: 987654, staff_strength: 40, is_active: true, created_at: "2012-01-25 11:24:48", updated_at: "2012-01-25 11:24:48", country_name: "Australia">
Read More…

Friday, January 27, 2012

csv file import / export in rails 3

by sandipransing 0 comments
CSV (comma separated values) files are frequently used to import/export data.
In rails 3, FasterCSV comes as default and below is the way to upload csv files inside rails applications. The code below will also show you how to generate csv in memory, parse on csv data, skip header, iterate over records, save records inside db, export upload error file and many more.
First, View to upload file
= form_tag upload_url, :multipart => true do %label{:for => "file"} File to Upload = file_field_tag "file" = submit_tag Assume upload_url maps to import action of customers controller
Controller code
class CustomersController < ApplicationController [...] def import if request.post? && params[:file].present? infile = params[:file].read n, errs = 0, [] CSV.parse(infile) do |row| n += 1 # SKIP: header i.e. first row OR blank row next if n == 1 or row.join.blank? # build_from_csv method will map customer attributes & # build new customer record customer = Customer.build_from_csv(row) # Save upon valid # otherwise collect error records to export if customer.valid? customer.save else errs << row end end # Export Error file for later upload upon correction if errs.any? errFile ="errors_#{Date.today.strftime('%d%b%y')}.csv" errs.insert(0, Customer.csv_header) errCSV = CSV.generate do |csv| errs.each {|row| csv << row} end send_data errCSV, :type => 'text/csv; charset=iso-8859-1; header=present', :disposition => "attachment; filename=#{errFile}.csv" else flash[:notice] = I18n.t('customer.import.success') redirect_to import_url #GET end end end [...] end Customer model
class Customer < ActiveRecord::Base scope :active, where(:active => true) scope :latest, order('created_at desc') def self.csv_header "First Name,Last Name,Email,Phone,Mobile, Address, FAX, City".split(',') end def self.build_from_csv(row) # find existing customer from email or create new cust = find_or_initialize_by_email(row[2]) cust.attributes ={:first_name => row[0], :last_name => row[1], :email => row[3], :phone => row[4], :mobile => row[5], :address => row[6], :fax => row[7], :city => row[8]} return cust end def to_csv [first_name, last_name, email, phone, mobile, address, fax, city] end end
Export customer records in CSV format
Below code loads customer records from database then generate csv_data inside memory and exports data to browser using send_data method.
Note: As we are not writing on file system hence code can easily work heroku. def export # CRITERIA : to select customer records #=> Customer.active.latest.limit(100) custs = Customer.limit(10) filename ="customers_#{Date.today.strftime('%d%b%y')}" csv_data = FasterCSV.generate do |csv| csv << Customer.csv_header custs.each do |c| csv << c.to_csv end end send_data csv_data, :type => 'text/csv; charset=iso-8859-1; header=present', :disposition => "attachment; filename=#{filename}.csv" end
Read More…

Friday, January 20, 2012

Mongoid embeded_in and Array field management

by sandipransing 0 comments
Previous post explains on mongoid document array field and rails form implementation
Below example shows rails form integration of array field of embedded mongoid document
consider scenario, student embeds one family who has many assets
class Student include Mongoid::Document field :name field :phone embeds_one :family validates_associated :family accepts_nested_attributes_for :family end
class Family include Mongoid::Document ASSETS = ['flat', 'car', 'business', 'bunglow', 'cash'] field :members, type: Integer field :assets, type: Array field :religon embedded_in :student end Brief controller code
class StudentsController < ApplicationController def new @student = Student.new @student.family ||= @student.build_family end def create @student = Student.new(params[:student]) @student.family.assets.reject!(&:blank?) if @student.save [...] else render :action => :new end end end view form will look like-
= form_for(@student) do |s| = s.text_field :name = s.text_field :phone - s.fields_for :family do |f| = f.text_field :members = f.text_field :religion - Family::ASSETS.each do |asset| /Here f.object_name #=> student[family] = f.check_box :assets, :name => "#{f.object_name}[assets][]", asset
Read More…

Thursday, January 19, 2012

mongoid array field and rails form

by sandipransing 0 comments
mongoid document supports array as field. array field in mongoid document is a ruby array but its quite complex to manage array field in rails forms.
After lot of google and reading comments from stack-overflow at last i felt helpless. Finally after doing research on rails form helper object(form_for, fields_for) am pleased to get it working as expected :)
In below example, product can have multiple categories
class Product CATEGORIES = %w(Apparel Media Software Sports Agri Education) include Mongoid::Document field :name, :type => String field :categories, :type => Array end Here is form code
= form_for(@product) do |f| = f.text_field :name - Product::CATEGORIES.each do |category| = f.check_box :categories, :name => "product[categories][]", category
Here is products controller code
class ProductsController < ApplicationController before_filter :load_product, :only => [:new, :create] [...] # We don't need new action to be defined def create @product.attributes = params[:product] # Here we need to reject blank categories @product.categories.reject!(&:blank?) if @product.save flash[:notice] = I18n.t('product.create.success') redirect_to(:action => :index) else render :action => :new end end [...] private def load_product @product = Product.new end end
Read More…

Tuesday, January 17, 2012

twitter-bootstrap form builder for rails

by sandipransing 0 comments
twitter-bootstrap is pluggable css suit provided by twitter.
To know more about how to get started on it click here
Below post will help you out in getting started bootstrap css with rails app. One need to add below files to helpers directory. MainForm can be used as base version of form builder and can be overriden for its subsequent use inside other custom form builders.
1. MainForm
# app/helpers/main_form.rb class MainForm < ActionView::Helpers::FormBuilder # NestedForm::Builder CSS = { :label => 'label-control', :hint => 'hint', :hint_ptr => 'hint-pointer', :error => 'help-inline', :field_error => 'error', :main_class => 'clearfix' } FIELDS = %w(radio_button check_box text_field text_area password_field select file_field collection_select email_field date_select) def main_class(error=nil) return CSS[:main_class] unless error [CSS[:main_class], CSS[:field_error]].join(' ') end def required(name) object.class.validators_on(name).map(&:class).include?(ActiveModel::Validations::PresenceValidator) rescue nil end def cancel(options={}) link = options.fetch(:return, "/") @template.content_tag(:a, "Cancel", :href => link, :class => "btn_form button np_cancel_btn #{options[:class]}") end def submit(value="Save", options={}) options[:class] = "send_form_btn #{options[:class]}" super end def label_class {:class => CSS[:label]} end def label_tag(attribute, arg) # Incase its a mandatory field, the '*' is added to the field. txt = arg[:label] && arg[:label].to_s || attribute.to_s.titleize txt<< '*' if(arg[:required] || required(attribute)) && arg[:required] != false label(attribute, txt, label_class) end def error_tag(method_name, attribute) errs = field_error(method_name, attribute) @template.content_tag(:span, errs.first, :class => CSS[:error]) if errs.present? end def field_error(method_name, attribute) return if @object && @object.errors.blank? return @object.errors[attribute] if method_name != 'file_field' @object.errors["#{attribute.to_s}_file_name"] | @object.errors["#{attribute.to_s}_file_size"] | @object.errors["#{attribute.to_s}_content_type"] end def hint_tag(txt) hintPtr = @template.content_tag(:span, '', :class => CSS[:hint_ptr]) hintT = @template.content_tag(:span, txt + hintPtr, {:class => CSS[:hint]}, false) end def spinner_tag @template.image_tag('spinner.gif', :class => :spinner,:id => :spinner) end end ZeroForm is custom form builder which is inherited from main_form and its going to be actually used inside forms. Feel free to make custom form related changes inside this
ZeroForm
cat app/helpers/zero_form.rb class ZeroForm < MainForm # Overridden label_class here as we dont need class to be applied def label_class {} end def self.create_tagged_field(method_name) define_method(method_name) do |attribute, *args| arg = args.last && args.last.is_a?(Hash) && args.last || {} # Bypass form-builder and do your own custom stuff! return super(attribute, *args) if arg[:skip] && args.last.delete(:skip) errT = error_tag(method_name, attribute) labelT = label_tag(attribute, arg) mainT = super(attribute, *args) baseT = @template.content_tag(:div, mainT + errT) hintT = hint_tag(arg[:hint]) if arg[:hint] spinnerT = spinner_tag if arg[:spinner] allT = labelT + baseT + spinnerT + hintT @template.content_tag(:div, allT, :class => main_class(errT)) end end FIELDS.each do |name| create_tagged_field(name) end end
In order to use Nested Forms you need to extend MainForm with NestedForm Builder
Integrate NestedForm with FormBuilder class MainForm < NestedForm::Builder end View Form
= form_for @address ||= Address.new, :builder => ZeroForm do |f| = f.text_field :street_address = f.text_area :detail_address, :rows => 2 = f.text_field :city = f.select :state, %w(US IN AUS UK UKRAINE) = f.submit 'Save & Continue', :class => 'btn primary' = link_to 'Skip »', '#'
To know more on twitter-bootstrap pagination in rails click here
Read More…

Get models list inside rails app

by sandipransing 0 comments
How to get collection of models inside your application. Certainly there are many ways to do it.
Lets have a look at different ways starting from worst -
Get table names inside database and then iterating over to get model name @models = ActiveRecord::Base.connection.tables.collect{|t| t.underscore.singularize.camelize} #=> ["AdhearsionAudit", "AudioLog", "AuditDetail","TinyPrint", "TinyVideo", "UnknownCall", "UserAudit", "User"]
Select those with associated class
@models.delete_if{|m| m.constantize rescue true}
Load models dir
@models = Dir['app/models/*.rb'].map {|f| File.basename(f, '.*').camelize.constantize.name } Select ActiveRecord::Base extended class only @models.reject!{|m| m.constantize.superclass != ActiveRecord::Base } Get Active Record subclasses
# make sure relevant models are loaded otherwise # require them prior # Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file } class A < ActiveRecord::Base end class B < A end ActiveRecord::Base.send(:subclasses).collect(&:name) #=> [...., A] How to get Inherited models too
class A < ActiveRecord::Base end class B < A end ActiveRecord::Base.descendants.collect(&:name) #=> [...., A, B] Below is more elegant solution provide by Vincent-robert over stack overflow which recursively looks for subsequent descendent's of class and gives you list from all over application
class Class def extend?(klass) not superclass.nil? and ( superclass == klass or superclass.extend? klass ) end end def models Module.constants.select do |constant_name| constant = eval constant_name if not constant.nil? and constant.is_a? Class and constant.extend? ActiveRecord::Base constant end end end
Read More…

Sunday, January 15, 2012

stripe gateway payment integration with rails

by sandipransing 0 comments
Stripe is simple website payment solution and its very easy to easy setup
It currently supports only in US and seems to be very popular compared to other payment gateways because of its api & pricing

Stripe API provides -
1. charge (regular payments)
2. subscription (recurring payments)
3. managing customers (via stripe_customer_token)

What you need to do ?
Create a stripe account by providing email address and password. There after go to the manage account page to obtain stripe public & api keys.
Rails Integration
# Gemfile gem stripe
# config/initializers/stripe.rb Stripe.api_key = "rGaNWsIG3Gy6zvXB8wv4rEcizJp6XjF5" STRIPE_PUBLIC_KEY = "vk_BcSyS2qPWdT5SdrwkQg0vTSyhZgqN"
# app/views/layouts/application.html.haml = javascript_include_tag 'https://js.stripe.com/v1/' = tag :meta, :name => 'stripe-key', :content => STRIPE_PUBLIC_KEY
Payment Form
# app/views/payments/new.html.haml #stripe_error %noscript JavaScript is not enabled and is required for this form. First enable it in your web browser settings. = form_for @payment ||= Payment.new, :html => {:id => :payForm} do |p| = p.hidden_field :stripe_card_token .field = p.text_field :amount .credit_card_form %h3.title Enter Credit Card - if @payment.stripe_card_token.present? Credit card has been provided. - else .field = label_tag :card_number, "Credit Card Number" = text_field_tag :card_number, nil, name: nil .field = label_tag :card_code, "Security Code (CVV)" = text_field_tag :card_code, nil, name: nil .field = label_tag :card_month, "Expiry Date" = select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} = select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"}
Javascript Code
# app/views/payments/new.js var payment; jQuery(function() { Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content')); return payment.setupForm(); }); payment = { setupForm: function() { $('.head').click(function() { $(this).css('disabled', true); if($('#payment_stripe_card_token').val()){ $('#payForm').submit(); } else{ payment.processCard(); } }); }, processCard: function() { var card; card = { number: $('#card_number').val(), cvc: $('#card_code').val(), expMonth: $('#card_month').val(), expYear: $('#card_year').val() }; return Stripe.createToken(card, payment.handleStripeResponse); }, handleStripeResponse: function(status, response) { if (status === 200) { $('#payment_stripe_card_token').val(response.id) $('#stripe_error').remove(); $('#payForm').submit(); } else { $('#stripe_error').addClass('error').text(response.error.message); $('.head').css('disabled', false); } } };
Generate & Migrate Payment Model
rails g model payment status:string amount:float email:string transaction_number:string rake db:migrate
Payment Model
# app/models/payment.rb class Payment < ActiveRecord::Base PROCESSING, FAILED, SUCCESS = 1, 2, 3 attr_accessible :stripe_card_token validates :amount, :stripe_card_token, :presence => true, :numericality => { :greater_than => 0 } def purchase self.status = PROCESSING customer = Stripe::Customer.create(description:email, card: stripe_card_token) # OPTIONAL: save customer token for further reference stripe_customer_token = customer.id # Charge charge = Stripe::Charge.create( :amount => amount * 100, # $15.00 this time :currency => "usd", :customer => stripe_customer_token ) if charge.paid self.transaction_num = charge.id self.status = SUCCESS else self.status = FAILED end return self rescue Exception => e errors.add :base, "There was a problem with your credit card." self.status = FAILED return self end end
Payments Controller
# app/controllers/payments_controller.rb class PaymentsController < ApplicationController def create @payment = Payment.new(params[:payment]) if @payment.valid? && @payment.purchase flash[:notice] = 'Thanks for Purchase!' redirect_to root_url else render :action => :new end end end
Read More…

Saturday, January 14, 2012

understanding rails uri

by sandipransing 0 comments
rails-uri module provide us with url manipulation methods
Parse string url url = URI.parse('http://funonrails.com/search/label/rails3') url.host #=> "http://funonrails.com" url.port #=> 80
URL with Basic Authentication
url = URI.parse('http://sandip:2121@funonrails.com/search/label/rails3') url.user #=> "sandip" url.password #=> "2121"
Extracting urls form string paragraph
URI.extract('http://funonrails.com is rails blog authored by http://sandipransing.github.com contact mailto://sandip@funonrails.com') #=> ["http://funonrails.com", "http://sandipransing.github.com", "mailto://sandip@funonrails.com"] Split & Join URI
URI.split('http://sandip:2121@funonrails.com/search/label/rails3') #=> ["http", "sandip:2121", "funonrails.com", nil, nil, "/search/label/rails3", nil, nil, nil] <=> [Scheme, Userinfo, Host, Port, Registry, Path, Opaque, Query, Fragment] URI.join('http://funonrails.com','search/label/rails3') #=> #
Escape & Unescape alias encode/decode URI
URI.escape('http://funonrails.com/search/?label=\\rails\3') URI.encode('http://funonrails.com/search/?label=\\rails\3') #=> "http://funonrails.com/search/?label=%5Crails%5C3" URI.unescape("http://funonrails.com/search/?label=%5Crails%5C3") URI.decode("http://funonrails.com/search/?label=%5Crails%5C3") #=> "http://funonrails.com/search/?label=\\rails\\3"
Match urls using regular expressions
"http://funonrails.com/search/label/rails3".sub(URI.regexp(['search'])) do |*matchs| p $& end #=> "http://funonrails.com/search/label/rails3"
Getting requested url inside rails
request.request_uri request.env['REQUEST_URI']
Getting previous page url inside rails
request.referrer
Read More…

Friday, December 30, 2011

Paypal payments integration with rails

by sandipransing 0 comments
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…

Authorize Net (SIM) payment integration with rails

by sandipransing 0 comments
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 here

Payment 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…

Thursday, December 29, 2011

Customizing rails default form builder

by sandipransing 0 comments
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…

Authorize Net Payment Gateway integration with rails

by sandipransing 0 comments
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…

Wednesday, December 28, 2011

railroady UML diagram generator for rails

by sandipransing 0 comments
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…

Bugging around Active Support's Class.class_attribute extension

by sandipransing 0 comments
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…

Authorize Net (AIM) payment integration with rails

by sandipransing 0 comments
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…

active-admin sass and rails 3

by sandipransing 0 comments
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…

About The Author

Sandip is a ruby on rails developer based in pune and also a blogger at funonrails. Opensource contributor and working with Josh software Private Limited. for more info read Follow Sandip on Twitter for updates.

Connect With Me...

Github Projects

@sandipransing Twitter