Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Rails Credit Card Model (See related posts)

A great example of a 'Credit Card' model I found on Pastie ( http://pastie.caboo.se/1157 ). There's no name or attribution.. so great work stranger!

class CreditCard < ActiveRecord::Base
  belongs_to :legal_entity
  validates_numericality_of :number, :only_integer => true
  validates_presence_of :number, :expiration_date, :card_type
  validates_uniqueness_of :number, :scope => 'account_id', :message => 'matches a credit card already on your account'
  belongs_to :account

  def validate
    errors.add("number", "is not a #{card_type} or is invalid") unless number_valid? && number_matches_type?
  end

  def self.card_types
    { 'Visa'             => 'visa',
      'MasterCard'       => 'mastercard',
      'Discover'         => 'discover',
      'American Express' => 'amex' }
  end

  def readable_card_type
    (@@card_types ||= self.class.card_types.invert)[card_type]
  end

  def digits
    @digits ||= number.gsub(/[^0-9]/, '')
  end

  def last_digits
    digits.sub(/^([0-9]+)([0-9]{4})$/) { '*' * $1.length + $2 }
  end

  protected
  def number_valid?
    total = 0
    digits.reverse.scan(/(\d)(\d){0,1}/) do |ud,ad|
      (ad.to_i*2).to_s.each {|d| total = total + d.to_i} if ad
      total = total + ud.to_i
    end
    total % 10 != 0
  end

  def number_matches_type?
    digit_length = digits.length
    case card_type
    when 'visa'
      [13,16].include?(digit_length) and number[0,1] == "4"
    when 'mastercard'
      digit_length == 16 and ("51" .. "55").include?(number[0,2])
    when 'amex'
      digit_length == 15 and %w(34 37).include?(number[0,2])
    when 'discover'
      digit_length == 16 and number[0,4] == "6011"
    end
  end
end

Comments on this post

pardeeb posts on Apr 25, 2008 at 11:17
I don't think the number_valid? method is correct. I think it will reject 10 percent of valid card numbers. The mod 10 routine should check == 10 and I think should not include the first 4 numbers.
pardeeb posts on Apr 25, 2008 at 13:13
For number_valid?, each should be each_char and the last line should be == instead of !=

You need to create an account or log in to post comments to this site.


Click here to browse all 5146 code snippets

Related Posts