Halaman

Rabu, 04 Agustus 2010

[shared] pac file for developing site using subdomain

saat ini saia mengerjakan site yg menggunakan subdomain tersendiri untuk setiap usernya, karenanya setiap saia meregistrasi user baru saia harus menambahkan line baru di hosts file saia:

127.0.1.1 localhost
127.0.1.2 mysite.local
127.0.1.3 www.mysite.local
127.0.1.5 user1.mysite.local
127.0.1.6 user2.mysite.local
...

hal tersebut cukup merepotkan terutama untuk testing.

sedikit googling saia menemukan site yang menjelaskan penggunaan pac (proxy auto-config) file untuk mempermudah develop subdomain site:
http://www.taylorluk.com/2009/08/hey-pac-man-sup-subdomains

tambahan, isi pac file yg saia gunakan saat ini untuk rails:

function FindProxyForURL(url, host) {
if (shExpMatch(host, "*.local")) {
return "PROXY 127.0.0.1:3000";
}
if (shExpMatch(host, "*.example.com")){
return "PROXY 127.0.0.1:3000";
}
return "DIRECT";
}

[shared] javascript arrayCompact

di RoR saia biasa menggunakan array.compact untuk memastikan di dalam suatu array tidak terdapat elemen nil. masalahnya javascript tidak mempunyai fungsi tersebut, untuk itu saia membuat fungsi kecil untuk melakukan hal td + sedikit tambahan untuk membuang bukan hanya null tetapi jg string kosong atau false:


/* return a copy of array with all null and optionally blank or false elements removed
* example:
* - arrayCompact(['a',null, 0, '', false]) //=> [ 'a', 0, '', false ] (only null removed)
* - arrayCompact(['a',null, 0, '', false], 1) //=> [ 'a', 0, false ] (only null and empty string removed)
* - arrayCompact(['a',null, 0, '', false], 2) //=> [ 'a' ] (all that equal to false removed)
*/
function arrayCompact(array, remove_level){
var new_array = new Array();
for(k in array)
if(typeof(array[k]) != 'undefined' &&
array[k] != null &&
!(remove_level > 0 &&
(typeof(array[k]) == 'string' || remove_level > 1) &&
array[k] == ''))
new_array.push(array[k]);
return new_array;
}


fungsi tersebut menggunakan plain javascript jadi dapat digunakan tanpa js framework apapun

[shared] Simple jQuery function for form debugging

dalam developing site, seringkali saia membuat form dengan elemen2 seperti select tag, radio button, input hidden dll. normalnya user hanya dapat memasukkan value2 yang sudah saia tentukan pada elemen2 tersebut, tp user yg "iseng" bisa saja memasukkan value di luar value2 yg sudah ditentukan td sehingga dapat merusak aplikasi.

buat mencegah saia harus membuat server side validation yang seringkali terlupakan karena pada saat saia melakukan testing saia melakukannya sebagai user normal bukan sebagai user "iseng". hal tersebut membuat saia berpikir untuk membuat script sederhana untuk mempermudah testing.

menggunakan jQuery ternyata script helper nya cukup simple:

function debugInput(){
$('.debug_input').remove();
$(':input:not(textarea,:text:not(.date),:button,:submit,:reset)').each(function(){
$(this).after('
'+this.name+':
').css('border', 'medium dotted gray');
});
$('form').each(function(){
$(this).append('
'+this.id+':
')
});
$('.debug_input').css('opacity', 0.7).draggable();
}


pada saat dijalankan fungsi tersebut akan menambahkan input text normal di tiap elemen2 form sehingga saia dapat dengan mudah memasukkan value2 aneh di select tag dan sejenisnya. selain itu fungsi ini jg menambahkan tombol submit di form.

contoh pemakaian pada site php manual:

Selasa, 25 Mei 2010

accept online payment for users (Part 1a: PayPal Website Payments Standard)

dah lama ga post, kali ini saia mao post artikel yg rasanya bakal lumayan panjang ;) tentang integrasi beberapa payment gateway (paypal, authorize.net, sagepay, google-checkout) buat nerima online payment untuk user (bukan untuk site owner).
jadi intinya site hanya sebagai perantara antara user dengan payment gateway.

ok mulai dari yg paling banyak digunakan: PayPal

persiapan yg dibutuhkan:
1. rails project dengan users (saia asumsikan dsini nama modelnya User)
2. developer account buat paypal (biar bisa nyoba) register di: https://developer.paypal.com/

siapkan model untuk menyimpan data paypal tiap user dan data notifikasi:

ruby script/generate model Paypal
ruby script/generate model Ipn


buat relasi user dengan paypal dan paypal dengan ipn, agar flexible saia menggunakan relasi polymorphic tapi relasi biasa juga dapat digunakan (saia anjurkan relasi paypal dengan ipn polymorphic agar nantinya kita mudah menambahkan gateway lain):

### paypal.rb ###
belongs_to :payable, :polymorphic => true
has_many :ipns, :as => :gateway, :dependent => :destroy


### ipn.rb ###
belongs_to :gateway, :polymorphic => true


### user.rb ###
include PaymentGatewayRelation


### /lib/payment_gateway_relation.rb ###
module PaymentGatewayRelation
def self.included(recipient)
recipient.class_eval do
has_one :paypal, :as => :payable, :dependent => :destroy

def payments
[self.paypal].compact
end

def payment_available?
!self.payments.empty?
end

def payment
self.payments.first
end

def payment= value
return unless value.respond_to? :payable
klass = value.class
self.payments.each{|x| x.destroy if x.class != klass}
self.reload
self.send("#{klass.to_s.underscore}=", value)
end
end
end
end

payment_gateway_relation.rb berisi relasi untuk semua gateway dan method2 untuk membantu akses.
mungkin akan lebih saia perjelas nanti saat gateway lain ditambahkan.

kemudian, tambahkan data paypal user yang dibutuhkan pada migration:

class CreatePaypals < ActiveRecord::Migration
def self.up
create_table :paypals do |t|
t.references :payable, :polymorphic => true
t.string :business, :limit => 70
t.string :return_url
t.timestamps
end
end

def self.down
drop_table :paypals
end
end


class CreateIpns < ActiveRecord::Migration
def self.up
create_table :ipns do |t|
t.references :gateway, :polymorphic => true
t.string :trans_id, :limit => 30
t.string :description, :limit => 50
t.timestamps
end
end

def self.down
drop_table :ipns
end
end

- business: paypal business account (email) dari user.
- return_url: url redirect untuk visitor ke suatu site (bisa di luar site kita) setelah pembayaran selesai
- trans_id: transaction id untuk mencegah duplikasi pembayaran
- description: optional, untuk menyimpan catatan ato suatu referensi

lanjut, di paypal.rb tambahkan attr_accessible dan beberapa validasi untuk keamanan ;)

include UriValidator

alias_attribute :account, :business

attr_accessible :business, :account, :return_url

validates_presence_of :account, :return_url
validates_uniqueness_of :business, :scope => :payable_type, :message => "account has already been used.", :case_sensitive => false
def validate
errors.add(:return_url, 'format invalid.') unless self.return_url.blank? || validate_http(self.return_url)
end

saia menggunakan alias attribute account untuk business agar lebih mudah dimengerti.

hal yang sama di ipn.rb

validates_presence_of :trans_id
validates_uniqueness_of :trans_id, :scope => :gateway_type, :allow_nil => true, :allow_blank => true

attr_accessible :trans_id, :description, :user, :gateway


buat ruby file /lib/uri_validator.rb:

module UriValidator

def validate_http uri
require 'uri'

return false if uri.blank?

uri = "http://" + uri unless uri.index("http") == 0

uri = URI.parse(uri)
if uri.class != URI::HTTP
return false
end

true
rescue URI::InvalidURIError
return false
end
end


fiuh.. urusan model2an beres..
migrate lalu selanjutnya controller dan view..
..
di post berikutnya biar kentang (sbenernya males nulis blog panjang2) =P

Jumat, 16 April 2010

[shared] to_xml_params with attributes from hash

sejauh yang saia tau, rails .to_xml dari hash tidak dapat menghasilkan xml tag dengan attribute selain type.
tetapi saia membutuhkan hal tersebut pada project yang saia kerjakan. karena itu saia membuat method to_xml_params untuk mengubah hash menjadi xml string:

def self.to_xml_params(data)
if data.is_a? Hash
data.collect do |key, value|
tag_attr = []
if key.is_a? Array
tag = key.first
key[1..-1].each do |key_attr|
key_attr.each do |k, v|
tag_attr << "#{k}=\"#{v}\""
end
end
else
tag = key
end
tag = tag.to_s.tr('_', '-')
result = "<#{tag}#{" #{tag_attr.join(' ')}" unless tag_attr.empty?}>"
result << to_xml_params(value)
result << "</#{tag}>"
result
end.join('')
elsif data.is_a? Array
data.inject(''){|result, v|
result << to_xml_params(v)
}
else
data.to_s
end
end


contoh penggunaan:


to_xml_params :a => "b"
# -> b
to_xml_params :a => {:b => "c"}
# -> c
to_xml_params [:a,{:x => :y}] => {:b => "c"}
# -> c
to_xml_params [:a,{:x => :y, :z => "w"}] => {[:b, {:p => "q"}] => "c"}
# -> c
to_xml_params :a => {:b => "c", :d => "e"}
# -> ec
to_xml_params :a => [{:b => "c"}, {:d => "e"}]
# -> ce sama dengan diatas