One of our newest clients, SaySwap Inc. facilitates video game swapping with their Ruby on Rails web application.
With video games going for $60 these days, people buy the game and beat it only to have it sit on a shelf somewhere gathering dust. SaySwap facilitates the trade for $4.95 USD.
It is interesting how successful a swapping system like this can be. With a user-base of over one million, and growing by hundreds daily, SaySwap facilitates game swapping by matching up a user’s ‘want list’ with other users’ ‘have lists’, and supports an entire community around it.
Game receivers get notified by email when someone is about to ship a ‘wanted’ game to you. Postage gets printed off from the game sender’s own printer on a handy little sheet of paper that gets folded to create the mailing envelope. The sender encloses the outside game jacket and game instructions along with the game (disc or cartridge).
Games usually arrive in about 1 week. If there are any problems with the game SaySwap takes care of it by giving you another ‘token’, which is good for receiving another game and refunds the ‘purchase points’ (virtual cost of the game).
Platforms supported are:
- Microsoft XBox
- Microsoft XBox 360
- Nintendo Game Boy Advance
- Nintendo Game Cube
- Nintendo DS
- Nintendo Wii
- Sony Playstation 2
- Sony Playstation 3
- Sony Playstation Portable
The big gamers, like Smaug317 and Dusktilldawn, save literally thousands of dollars and trade hundreds of games. However, even the occasional gamer, like myself, saves up to $200.00 after trading just four games.
Anyway, gamers take note… I have just released the ’SaySwap Most Traded Video Games’ Google homepage widget, which pulls the RSS feed and displays the top x number of traded video games over a configurable number of days. You can also customize the feed to display only a certain platform, for you game bigots.
If you want to parse the feed yourself or subscribe to it using your own reader here is the link: http://www.sayswap.com/rest/games/swaps
As promised here is the second article about validating credit cards with Ruby.
This edition wraps a module and class around the code in preparation for future enhancement.
Feel free to change whatever you want. If you do please send me an update and at least give me credit for the original.
To use it just do something like this in your controller:
if params[:cc]
begin
cc = Payment::CreditCard.new(params[:cc])
cc.valid?
@user.update_attribute(:verified_at, Time.now)
rescue Exception => e
logger.debug e.inspect
flash[:notice] = "Your profile has been updated. However, #{e}."
return
end
endThis assumes you have a form like this somewhere in your view:
<p><label>Name On Card</label><%= text_field :cc, :name, :class => "text-n" %></p>
<p><label>Card Type</label><%= select :cc, :card_type, FundingSource.get_card_types %></p>
<p><label>Card Number</label><%= text_field :cc, :number, {:size => 16, :maxlength => 16, :class => "text-n"} %><br />
<label></label><small>(15-16 digits)</small></p>
<p><label>Expiration Date</label><%= date_select :cc, :expiration,
:start_year => Time.now.year,
:end_year => Time.now.year+10,
:use_month_numbers => true,
:discard_day => true,
:include_blank => true,
:order => [:month, :year] %></p>
<p><label>Security Code</label><%= text_field :cc, :security_code, :size => 4, :class => "text-s" %><br />
<label></label><small>(3 Digit Code on back of credit card)</small></p>Obviously, this code comes with no warranty of any kind and could hurt your application, your data, your home, your feelings, etc. Don’t sue me. Other than that, use it as you see fit. Just please give me some credit.
module Payment
class CreditCard
CARD_TYPE = {
:master_card => 0,
:visa => 1,
:american_express => 2,
:diners_club => 3,
:discover => 4
}
###################################################################
# Construct the object and do minimal validation
# Params:
# :name - cardholder's name (optional, for future use)
# :card_type - type of card (required)
# :number - 15-16 digit card number (required)
# :security_code - 3-4 digit security code (required, only
# needs to exist and be the right length)
# 'expiration(1i)' - expiration year (required).
# 'expiration(2i)' - expiration month (required).
###################################################################
def initialize(attributes = {})
# Cardholders Name
if (@name = attributes[:name]).nil? or @name.empty?
raise "Cardholder Name is required"
return
end
# Card Type
@card_type = attributes[:card_type]
@card_type = convert_cc_type(@card_type)
if @card_type.nil? or !CARD_TYPE.has_value?(@card_type)
raise "A valid Card Type is required"
return
end
# Card Number
if (@number = attributes[:number]).nil? or @number.to_i.nil? or
@number.length < 15
raise "A valid Card Number is required"
return
end
# Security Code
if ((@security_code = attributes[:security_code]).nil? or
@security_code.to_i.nil? or
(@security_code.length != 3 and
@card_type != CARD_TYPE[:american_express]) or
(@security_code.length != 4 and
@card_type == CARD_TYPE[:american_express]))
raise "A valid Security Code Number is required"
return
end
# Card Expiration
if ((@card_expiration_month = attributes['expiration(2i)']).nil? or
@card_expiration_month.to_i.nil? or
@card_expiration_month.to_i < 1 or
@card_expiration_month.to_i > 12)
raise "A valid Card expiration month is required"
return
end
if ((@card_expiration_year = attributes['expiration(1i)']).nil? or
@card_expiration_year.to_i.nil?)
raise "A valid Card expiration year is required"
return
end
@card_expiration_date = Time.gm("#{@card_expiration_year}".to_i,
@card_expiration_month).next_month
if (@card_expiration_date <= Time.now)
raise "Card is expired."
return
end
end
###################################################################
# Check number format for given card type and check whole number
# against the Mod 10 algorithm
###################################################################
def valid?
valid_format = false
pass_check = false
# check format
case @card_type
when CARD_TYPE[:master_card]
valid_format = @number[/^5[1-5][0-9]{14}$/] == @number
when CARD_TYPE[:visa]
valid_format = @number[/^4[0-9]{12}$|^4[0-9]{15}$/] == @number
when CARD_TYPE[:american_express]
valid_format = @number[/^3[4|7][0-9]{13}$/] == @number
when CARD_TYPE[:diners_club]
valid_format = @number[/^30[0-5][0-9]{11}$|^3[6|8][0-9]{12}$/] == @number
when CARD_TYPE[:discover]
valid_format = @number[/^6011[0-9]{12}$/] == @number
end
raise "credit card number is invalid." if valid_format == false
# check Mod 10
reverse_card_num = @number.reverse
sum = 0
reverse_card_num.scan(/./).each_with_index do |digit, index|
digit = digit.to_i
digit *= 2 if index % 2 != 0
if digit.to_s.length == 2
first_num = digit.to_s[0..0]
second_num = digit.to_s[1..1]
digit = first_num.to_i + second_num.to_i
end
sum += digit
end
pass_check = sum % 10 == 0 ? true : false
raise "credit card is invalid." if pass_check == false
true
end
###################################################################
# Return a safe (masked) credit card number
# char is the mask character, count is the number of last x digits
# to display unmasked
###################################################################
def masked_number(char = 'X', count = 4)
len = @number.to_s.length
card_number = char * (len - count)
card_number << @number[-count..-1]
end
###################################################################
private
###################################################################
###################################################################
# This allows the user to pass raw_type = 'visa',
# 'american express', etc.
###################################################################
def convert_cc_type(raw_type)
card_type = nil
if raw_type.is_a?(String)
card_type = CARD_TYPE[raw_type.downcase.gsub(' ', '_').to_sym]
else
card_type = raw_type
end
end
end
endOlder posts: 1 2
