รวม links อีกที ไม่ว่างครับ งานเยอะ

Cucumber: The Latest in Ruby Testing
Delayed Gratification with Rails
What’s New in Edge Rails: render Stops Being High-Maintenance
What’s New in Edge Rails: Object.try
HappyMapper: Easy XML / Object Mapping for Rubyists (อันนี้หน้าตาดี)
JBoss on Rails: DeployinRails Podcast Brasil, QCon Special - John Straw (YellowPages.com) and Matt Aimonetti (Merb)g Rails Apps to a JBoss App Server (เจ๋ง)
jnunemaker: jQuery on Rails: Why Bother?
Rails Podcast Brasil, QCon Special - John Straw (YellowPages.com) and Matt Aimonetti (Merb)
Rails Profiling: Getting Easier
Git’n Your Shared Host On
Episode 137: Memoization
jnunemaker: RubyGems: Yours, Mine and Ours

Comments 2 Comments »

ไม่ได้หายไปไหน งานเยอะครับ กับหัด emacs อยู่ ไว้หัด emacs สำเร็จแล้ว คงจะได้มาเขียนบ่อยขึ้น

3 Ways To Build Fake Demo Data For Your Rails App

ถ้าจะสร้างข้อมูลหลอกๆ มาใช้งาน สามารถทำได้ง่ยๆ ด้วย
http://faker.rubyforge.org/
http://random-data.rubyforge.org/
http://github.com/sevenwire/forgery/tree/master

ทุกวันนี้ผมเขียนเป็น array เก็บไว้ แล้ว random ออกมาแล้ว save ต่อไปคงจะสบายขึ้นด้วยเครือ่งมือพวกนี้

———————————————————————————

What’s New in Edge Rails: Default Scoping

feature ใหม่สำหรับ active record คือ default_scope
ชื่อก็สื่อความหมายได้ง่ายๆ อยู่แล้ว

มาดูหน้าตาหน่อย

class Article  'created_at DESC'Article.published #=> "SELECT * FROM `articles` WHERE published = true ORDER BY created_at DESC"
  named_scope :published, :conditions => { :published => true }
end

Article.published #=> "SELECT * FROM `articles` WHERE published = true ORDER BY created_at DESC"

ก็ใส่ condition ให้เป็น default ในทุกๆ ครั้งที่มีการ query

รวมกันเลยละกัน

What’s New in Edge Rails: Application.rb Duality is no More

อีกหน่อย application.rb จะเป็น application_controller แล้ว
สั้นๆ เหอๆ

———————————————————————————————

Rails 2.2 Released
Rails 2.2 Released - 27 Links and Resources To Get You Going

หลักๆ คงจะหนักไปที่เรื่อง i18n
thread safe
รองรับ jruby/ruby 1.9
และอีกหลายๆ อย่างที่ผมเคยรายงานไปแล้วในข่าวเก่าๆ ครับ อย่าง etag/connection pool

ประมาณนี้ครับ

Comments No Comments »

อย่างที่รู้ๆ กันว่าโครงสร้างข้อมูลแบบ Hash มันไม่มีการเรียงลำดับ คงเป็นเพราะว่าธรรมชาติของข้อมูลนั้นไม่ต้องการการเรียงลำดับ แต่ว่านะ ก็มีบางครั้งที่เราอยากจะได้ที่มันเรียงลำดับด้วยล่ะ (อย่างงานที่ผมเจอวันนี้) จะทำไง

Hash ธรรมดาก็คงไม่เพียงพอซะแล้ว

ที่ ActiveSupport ของ Rails ก็ได้เตรียมการสำหรับเรื่องนี้ไว้แล้ว มันมี OrderedHash ใว้ให้เราใช้กัน

>> h = ActiveSupport::OrderedHash.new
=> []
>> h["x"] = "xx"
=> "xx"
>> h["z"] = "zz"
=> "zz"
>> h["y"] = "yy"
=> "yy"
>> h
=> [["x", "xx"], ["z", "zz"], ["y", "yy"]]
>> h["y"]
=> "yy"

ต้องเขียนอย่างนี้ครับ หากเขียนแค่ OrderedHash.new ตอนที่ใช้งานที่ controller มันจะบอกว่าไม่รู้จัก

จากนั้นเราก็เอาไปใช้ได้ตามใจ และหากเราเอา Hash ตัวที่เราสร้างมา view ข้อมูลดูก็จะเห็นว่ามันเรียงลำดับตามที่เราใส่ลงไป

จะเห็นว่าจริงๆ แล้วมันไม่ได้เป็น Hash จริงหรอกนะ มันเป็น Array แต่สามารถเข้าถึงข้อมูลได้คล้ายๆ Hash เท่านั้นเอง

อืม… Magic จริงๆ เลย

Comments 1 Comment »

Roxy - An Object Proxying Library for Ruby

Roxy ช่วยทำ proxy ง่ายๆ ให้กับ object ที่มีความสัมพันธ์กัน ยกตัวอย่าง

require 'roxy'
class Person

# Add in proxy ability
include Roxy::Moxie

attr_accessor :first, :last, :parents, :children

# Add ability to ask the parents collection if they are divorced
proxy :parents do
def divorced?
proxy_target.size > 1 and
proxy_target.collect { |parent| parent.last }.uniq.size > 1
end
end

# Add ability to ask the children collection for only the step-children
proxy :children do
def step
proxy_target.select { |child| proxy_owner.last != child.last }
end
end

def initialize(first, last)
@first, @last = first, last
end
end

# Now the following is possible:
person.parents.divorced? #=> true|false
person.children.step #=> [<Person...>, <Person...>]

ขออภัย สำหรับ indent จิ้มไปจิ้มมา มันเอา indent ออกหมดเลยครับ ผมขี้เกียจต่อสู้กับมันละ ==’

idea ของการทำ proxy นี้ ก็อารมณ์ประมาณ has_many :associated_objects ของ active record แหละครับ ทำให้เราเรียกใช้อะไรต่างๆ ใน class ที่เราอยากจะให้มีความสัมพันธ์ได้

———————————————————————————————————————————–

Creating and Integrating Bookmarklets with Rails

video ตัวอย่างการสร้าและ integrate bookmarklets

————————————————————————————————————————————-

Rails Envy Podcast - Episode #055: 11/12/2008

Subscribe via iTunes - iTunes only link.
Download the podcast ~26:30 mins MP3.
Subscribe to feed via RSS by copying the link to your RSS Reader

Comments No Comments »

บังเอิญต้องไปทำเว็บด้วย Drupal แล้วก็มีข้อมูลจากเว็บเก่าที่ต้องโอนย้ายมา ด้วยความช่วยเหลือจากนิสิตหลาย ๆ ท่าน ในการเขียนโปรแกรมแกะข้อมูลจากเว็บเก่า ปัญหาก็เหลือแค่ว่าจะเอาไปใส่ใน Drupal ได้อย่างไรง่าย ๆ

ผมได้ข่าวว่ามี API แต่ก็หาไม่เจอ แถมรีบอีก.. ก็เลย… ตกลงเขียนเองเลย โดยใช้ Active Record เข้าไปครอบตารางของ Drupal

แม้ว่าตารางของ Drupal จะเยอะแยะ แต่ก็ไม่เกินความสามารถในการปรับแต่ง Active Record (และ gem อื่น ๆ)

ใน Drupal ทุกอย่างเป็น node ดังนั้นตารางพื้นฐานของ Drupal คือตาราง node ซึ่งมีอะไรที่คล้าย ๆ กับ id คือ nid กับ vid โดย nid คือหมายเลขโหนด และ vid คือหมายเลข revision (โหนดหนึ่ง ๆ แก้ได้หลาย revision) ทีนี้มีปัญหาอีกนิดคือในตาราง node มีฟิลด์ชื่อ type ซึ่งจะไปชนกับการใช้ single-table inheritance ใน Active Record ทำให้เราต้องหลบชื่อดังกล่าวไปเป็นชื่ออื่น (ในด้านล่างใช้เป็น type_id)

ดังนั้นสิ่งที่ไม่ตรงกับ convention ของ Rails ที่ต้องปรับคือ table_name, primary_key และ inheritance_column โมเดลของ node แสดงด้านล่าง

class Node < ActiveRecord::Base
  self.inheritance_column = 'type_id'
  set_table_name "node"
  set_primary_key "vid"
end

ใน Drupal ผมใช้โมดูล CCK สำหรับใช้สร้างประเภท (content type) ของ node ทีนี้ ผมมีการสร้างประเภท lect_profile เอาไว้ ซึ่ง Drupal จะไปสร้างตารางชื่อ content_type_lect_profile เอาไว้

ไล่ไปไล่มา ก็พบว่ามันเชื่อมกับตาราง node ด้วย field vid ทำให้เราเพิ่ม model และความสัมพันธ์ดังกล่าวเข้าไปใน Node ได้ดังด้านล่าง

class Node < ActiveRecord::Base
  # ...
  has_one :profile,
          :class_name => 'Profile',
          :foreign_key => 'vid'
end

class Profile < ActiveRecord::Base
  set_table_name "content_type_lect_profile"
  set_primary_key "vid"
end

พอเชื่อมได้แล้ว ก็ยังมีเรื่องยุ่งยากก็ตามมาอีก เพราะว่าในประเภทที่สร้างมีฟิลด์ที่มีค่าได้หลายค่า คือประวัติการศึกษา ทีนี้ใน Drupal จะเก็บข้อมูลโดยใช้ primary key ประกอบด้วย vid กับ delta (delta คือบอกว่าเป็นข้อมูลค่าที่เท่าใด)

ทีนี้ชักมึนครับ.. เพราะว่าใน Active Record จะต้องใช้ primary key เป็นหลักในการลบหรือปรับค่าเสมอ

แต่ก็โชคดี (รอดตาย) เพราะว่ามีคนทำ gem Composite Primary Keys เอาไว้ครับ!

(ในการติดตั้ง Composite Primary Key ถ้าเป็นรุ่นล่าสุดจะต้องใช้ Rails 2.2.0 ซึ่งยังไม่ออก ถ้าต้องการรุ่นที่ใช้ได้ สามารถติดตั้งรุ่น 1.1.0 แทน ด้วยคำสั่ง gem install composite_primary_keys -v 1.1.0)

ด้วย gem ดังกล่าว เราสามารถเพิ่มการเชื่อมโยงระหว่าง Profile กับโมเดล EduHistory ได้ดังด้านล่าง

class Profile < ActiveRecord::Base
  # ...
  has_many :edu_histories,
           :class_name => 'EduHistory',
           :foreign_key => 'vid'
end

class EduHistory < ActiveRecord::Base
  set_table_name "content_field_edu_history"
  set_primary_keys :vid, :delta
end

ทำเสร็จ เรียกใช้สคริปต์ปรับค่า ปรากฏว่าทุกอย่างหายกลายเป็นสตริงว่าง! ปรากฏว่าทำ encoding ผิด เพราะว่าข้อมูลจากเว็บเก่าเป็น tis620 ของใหม่เป็น utf8

ทีนี้ก็เลยต้องไปพึ่ง iconv ด้วยเมท็อดด้านล่าง

require 'iconv'
def to_utf(st)
  Iconv.conv('utf-8','tis620',st)
end

แก้เสร็จ ปรับค่าเรียบร้อย ดูฐานข้อมูลปรับค่าตามต้องการ รีโหลด Drupal ไม่มีอะไรเปลี่ยน!

ตกใจไปสักพัก

Drupal มี cache! ใน Drupal 6 สั่งให้ clear cache ได้ที่หน้า Admin -> Site Config -> Performance ครับ

Comments No Comments »

Scaling Ruby Envycast

วิธีเขียน ruby app ให้เร็วขึ้น video ละ 9 เหรียญ เชิญเลือกชมได้

—————————————————————————————————

Merb 1.0 Released So Here’s 44 Links and Resources To Get You Going

Merb 1.0 ออกอย่างเป็นทางการแล้ว มี 44 links ที่เป็น resources ในการหาข้อมูลเกี่ยวกับ merb

44 links เยอะมาก ลองดูครับ

————————————————————————————————————

Episode 135: Making a Gem

ทำ gem ให้ชาวบ้านใช้ ไม่ยาก

Comments 2 Comments »

ใน blog ก่อนหน้านี้พูดถึง Nginx -> Mongrel cluster <- Monit ปรากฏว่า monit มันไม่สามารถไปคุมเจ้า mongrel cluster ได้ คาดว่าเป็นเพราะ Mongrel cluster มันเป็น cluster จึงไม่ได้แยกแต่ละตัวออกเป็น process เดี่ยวๆ แบบที่ monit ชอบ ดังนั้นเลยลองวิธีใหม่ แยกมันเป็น 3 ตัวซะเลย

ตอนนี้เจ้า monit ควบคุม mongrel อยู่หมัด ผมลอง kill process ดู เจ้า monit ก็ start ขึ้นมาให้ ตอนนี้สั่งปิด/เปิด mongrel จาก monit ได้เลย

ขั้นตอนการติดตั้งจะซ้ำกับของเดิมเยอะหน่อย แต่อยากเขียนให้เต็มๆ ครับ เริ่มจาก

1. ติดตั้ง project ของเรา

Add new user

# สำหรับ ubuntu
sudo /usr/sbin/adduser mongrel 

# สำหรับ redhat ที่ใส่ -r เพราะไม่ต้องสร้าง home ให้ user
sudo /usr/sbin/adduser -r mongrel

Deploy application

sudo mkdir /var/www
sudo mkdir /var/www/project
sudo chown -R mongrel:mongrel /var/www/project

cd /var/www/project
su mongrel
svn checkout svn://host.com/project/trunk/ --username xxx --password xxx .
rake db:create:all
rake db:migrate
rake db:migrate RAILS_ENV="production"

#ทดสอบว่าติดตั้งเรียบร้อยหรือเปล่า ก่อนเริ่มขั้นตอนต่อไป
./script/server

2. ให้แก้ไฟล์ mongrel_rails ให้ลบ PID ออกถ้ามี PID อยู่แล้ว เพราะถ้าไม่ทำเจ้า mongrel_rails จะ error ตอนที่ process ของเราตายโดยทิ้ง PID เอาไว้ แล้วเราพยายาม start mongrel ขึ้นมา มันจะฟ้องว่ามี PID อยู่แล้ว และไม่ยอม start ให้เรา

สั่ง edit mongrel_rails ใครถนัด editor ตัวไหนก็ใช้ตามสะดวกนะครับ

sudo vi /usr/lib/ruby/gems/1.8/gems/mongrel-1.1.5/bin/mongrel_rails

#บางทีก็อยู่ที่นี่
sudo /var/lib/gems/1.8/gems/mongrel-1.1.5/bin/mongrel_rails

แทนที่บรรทัดนี้

          if File.exist? defaults[:pid_file]
            log "!!! PID file #{defaults[:pid_file]} already exists.  Mongrel could be running already.  Check your #{defaults[:log_file]} for errors."
            log "!!! Exiting with error.  You must stop mongrel and clear the .pid before I'll attempt a start."
            exit 1
          end

ด้วยบรรทัดนี้

          if File.exist? defaults[:pid_file]
            # mongrels that crash can leave stale PID files behind, and these
            # should not stop mongrel from being restarted by monitors...
            pid = File.new(defaults[:pid_file]).readline
            unless `ps -ef | grep #{pid} | grep -v grep`.length > 0
              # use "ps ax" for freebsd
              log "!!! PID file #{defaults[:pid_file]} exists, but is stale, and will be deleted so that this mongrel can run."
              File.delete(defaults[:pid_file])
            else
              log "!!! PID file #{defaults[:pid_file]} already exists and the process id referred to in it is running.  This mongrel is probably already running.  #{defaults[:log_file]} for errors.  EXITING."
              exit 1
            end
            exit 1
          end

3. เตรียม config สำหรับ mongrel ทั้ง 3 ตัว

sudo vi /var/www/project/config/mongrel_8000.yml
---
user: mongrel
cwd: /var/www/project
log_file: log/mongrel.8000.log
port: "8000"
environment: production
group: mongrel
address: 127.0.0.1
pid_file: tmp/pids/mongrel.8000.pid
daemon: true

สร้างไฟล์นี้อีกสองไฟล์ แต่เปลี่ยนจาก 8000 เป็น 8001 และ 8002

สำหรับคนที่ลง mongrel cluster ไปแล้ว แถมสั่งให้มัน start ตอน boot ด้วย ต้องไปเอาออกก่อนครับ เพราะต่อไปเราจะให้ monit เป็นคน start ให้ทั้งหมด ผมใช้วิธีลบ ไฟล์ /etc/mongrel_cluster/application_name.yml ออกไป

ทดสอบว่า server ของเราทำงานโดยสั่ง

sudo /usr/bin/mongrel_rails start -C /var/www/project/config/mongrel_8000.yml

จากนั้นทดลองสั่ง

ps -aux | grep mong

ถ้ามี process 8000 ของเราขึ้นมาแสดงว่าเรียบร้อย ถ้าไม่ขึ้นให้ลองไปดู log ที่ /var/www/project/log/mongrel.8000.log

จากนั้นลองสั่ง stop ดูด้วยคำสั่ง

sudo /usr/bin/mongrel_rails stop -P /var/www/project/tmp/pids/mongrel.8000.pid

ถ้าไม่ได้ให้ลองดู log เหมือนเดิม ถ้าได้ก็ไปขั้นตอนต่อไปได้เลย

4. ติดตั้ง Watch dog ที่ชื่อ monit

ติดตั้ง monit (ถ้าใครไม่มี apt-get ใช้ก็ลองประยุกต์ใช้ทางอื่นดูนะครับ)

sudo apt-get install monit

จากนั้นตั้งค่าให้ monit

sudo mkdir /etc/monit.d
sudo vi /etc/monit.d/mongrel.monitrc

ใส่ config ตามนี้

check process mongrel_8000
  with pidfile /var/www/project/tmp/pids/mongrel.8000.pid
  group mongrel
  start program = "/usr/bin/mongrel_rails start -C /var/www/project/config/mongrel_8000.yml"
  stop program = "/usr/bin/mongrel_rails stop -P /var/www/project/tmp/pids/mongrel.8000.pid"
  if failed host 127.0.0.1 port 8000 protocol http
      and request "/" then alert
  if totalmem is greater than 110.0 MB for 4 cycles then restart
  if cpu is greater than 80% for 4 cycles then restart
  if 3 restarts within 5 cycles then timeout

check process mongrel_8001
  with pidfile /var/www/project/tmp/pids/mongrel.8001.pid
  group mongrel
  start program = "/usr/bin/mongrel_rails start -C /var/www/project/config/mongrel_8001.yml"
  stop program = "/usr/bin/mongrel_rails stop -P /var/www/project/tmp/pids/mongrel.8001.pid"
  if failed host 127.0.0.1 port 8001 protocol http
      and request "/" then alert
  if totalmem is greater than 110.0 MB for 4 cycles then restart
  if cpu is greater than 80% for 4 cycles then restart
  if 3 restarts within 5 cycles then timeout

check process mongrel_8002
  with pidfile /var/www/project/tmp/pids/mongrel.8002.pid
  group mongrel
  start program = "/usr/bin/mongrel_rails start -C /var/www/project/config/mongrel_8002.yml"
  stop program = "/usr/bin/mongrel_rails stop -P /var/www/project/tmp/pids/mongrel.8002.pid"
  if failed host 127.0.0.1 port 8002 protocol http
      and request "/" then alert
  if totalmem is greater than 110.0 MB for 4 cycles then restart
  if cpu is greater than 80% for 4 cycles then restart
  if 3 restarts within 5 cycles then timeout

ถ้าเจ้า monit เจออะไรผิดพลาด ตามที่เขียนใน config มันจะ restart ให้ทันที อันนี้ชอบมั๊กๆ แต่เปิดใช้มาหลายวัน มันยังไม่เคย restart เองเลยครับ เสถียรมาก มีแต่ผมสั่งมัน restart เอง คงเพราะ ผู้ใช้ยังไม่คุ้นเลยยังยิงกันไม่ถึงตาย

แก้ไฟล์ monit ให้มัน start ตอน boot เครื่อง

sudo vi /etc/default/monit

startup=1

จากนั้นเอา comment ของไฟล์ monitrc ออกตามนี้

sudo vi /etc/monit/monitrc

set daemon 120
set logfile syslog facility log_daemon
set httpd port 2812 and
allow localhost # allow localhost to connect to the server and
include /etc/monit.d/*

ทดสอบการทำงานของ monit ตามนี้ครับ

สั่ง restart, sudo shutdown -r now
เมื่อเปิดมาตอนแรกให้รอ 5-10 นาที
จากนั้นลอง sudo monit status
ตัว monit ควรจะ start mongrel ให้เราทั้งสามตัว
ทดลอง ps -aux | grep mong
ดู process ทั้งหมดของ mongrel
ทดลอง kill 1 process
รอ 5-10 นาที
ทดลอง ps -aux | grep mong
ดูว่า mongrel start ขึ้นมาให้เราหรือเปล่า
แล้วสั่ง sudo monit status
ดูว่า monit รับรู้การขึ้นมาหรือยัง
ถ้าขึ้นมาครบทั้ง 3 ตัวเป็นอันว่าติดตั้ง mongrel และ monit สำเร็จ

คำสั่งที่ใช้บ่อยบน monit มีดังนี้ครับ

# restart monit ถ้ามันหือ
sudo /etc/init.d/monit restart 

#restart mongrel ยกฝูง
sudo monit restart all -g mongrel

#start/stop บางตัว
sudo monit stop mongrel_8000
sudo monit start mongrel_8000

#ดู status
sudo monit status

#force ให้ monit ตรวจสอบการทำงานของ process ที่มันดูอยู่
sudo monit validate

5. ติดตั้ง NGiNX

sudo apt-get install nginx

แก้ config ของไฟล์

sudo vi /etc/nginx/nginx.conf
#user deploy;
worker_processes  1;

error_log  /var/log/nginx/error.log;
#error_log   logs/error.log debug;
#pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    #tac_nonpush  on;
    tcp_nodelay   on;

    #access_log /var/log/nginx/access.log;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    #keepalive_timeout  65;

    gzip            on;
    gzip_min_length 1100;
    gzip_buffers    4 8k;
    gzip_types      text/plain;

    #include /etc/nginx/sites-enabled/*;

    upstream mongrel {
        server 127.0.0.1:8000;
        server 127.0.0.1:8001;
        server 127.0.0.1:8002;
    }

    server {
        listen  80;
        server_name project.com;
        root /var/www/project/public;
        index  index.html index.htm;
        location / {
          proxy_set_header  X-Real-IP  $remote_addr;
          proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_redirect false;
          if (-f $request_filename/index.html) {
            rewrite (.*) $1/index.html break;
          }
          if (-f $request_filename.html) {
            rewrite (.*) $1.html break;
          }
          if (!-f $request_filename) {
            proxy_pass http://mongrel;
            break;
         }
       }
       error_page   500 502 503 504  /50x.html;
       location = /50x.html {
         root   html;
       }
    }
}

restart NGiNX ด้วยคำสั่ง

sudo /etc/init.d/nginx restart

จากนั้นลองเข้าผ่าน web ดูครับ ว่าเปิดได้หรือเปล่า ถ้าได้ก็จบครับ ขั้นต่อไปเป็นของแถม ทำเผื่อเอาไว้ตอนมีปัญหาจะได้เข้ามาดู

6. ติดตั้งตัว monitor ให้ NGiNX

sudo apt-get install rrdtool librrds-perl -y
sudo vi /etc/nginx/nginx.conf

เพิ่ม location status ลงไประหว่าง http และ server

http {
    ...
    server {
        listen SOME.IP.ADD.RESS;
        ...
        location /nginx_status {
            stub_status on;
            access_log   off;
            allow SOME.IP.ADD.RESS;
            deny all;
        }
        ...
    }
    ...
}

ทดสอบว่า script NGiNX ของเรายัง ok อยู่

# sudo /usr/sbin/nginx -t
2006/04/29 04:24:36 [info] 31676#0: the configuration file /opt/nginx/conf/nginx.conf syntax is ok
2006/04/29 04:24:36 [info] 31676#0: the configuration file /opt/nginx/conf/nginx.conf was tested successfully

สร้างที่อยู่ให้ output file

sudo mkdir /opt/rrd
sudo mkdir /opt/rrd/html

sudo vi /etc/nginx/rrd_nginx.pl

ไฟล์ rrd_nginx.pl เอาได้ที่ apirak.com/downloads/rrd_nginx.pl

อย่าลืมสั่งให้ rrd_nginx.pl กลายเป็น execute file ด้วย

chmod +x /etc/nginx/rrd_nginx.pl

จากนั้น edit ให้ cron เรียก rrd_nginx.pl ทุกๆ นาที

sudo crontab -e

# m h  dom mon dow   command
  * *  *   *   *     /etc/nginx/rrd_nginx.pl

เมื่อโปรแกรมทำงานจะมีรูปขึ้นมาที่ /etc/opt/rrd/html สามารถเข้าไปดูได้ วินาทีนี้ผมยังไม่ได้สร้าง HTML สำหรับดู เลยทำแค่ ใช้ feh ในการดู

sudo apt-get install feh -y
feh /opt/rrd/html/*.png

ถ้ามีกราฟขึ้นก็แสดงว่าโปรแกรมทำงานได้แล้ว และถ้ากราฟมีขึ้นๆ ลงๆ ก็แสดงว่าสมบูรณ์ละแล้วครับ :)

Reference ( บางแหล่งก็ลืมไปแล้วครับ จดไว้ประมาณนี้)

http://codesnippets.joyent.com/tag/mongrel
http://www.howtoforge.com/server_monitoring_monit_munin
http://www.circlingminds.com/advanced-rails/using-nginx-mongrel-rails-on-ubuntu/
http://wiki.codemongers.com/NginxInstall
http://groups.google.com/group/thinking-sphinx/browse_thread/thread/a7a11ab1c98f5593
http://mkaz.com/ref/unix_cron.html

Comments 1 Comment »

RailsRumble 2008 Winners Announced

1st
MeetInBetween.us
app นี้ง่ายๆ เล่นกับ google map ด้วย ให้ใส่ address ไปสองจุด แล้วมันจะหาจุดตรงกลางเป็นตัวบอกว่า จะเจอกันที่ไหน หรือเพิ่มอีกหลายๆ จุด มันก็จะหาจุดตรงกลางให้ เหมาะสำหรับนัดกันไปดูบอล หรือกินหมูกะทะ แล้วไม่รู้จะไปดูหรือกินไหนดี lol

2nd
QFlip
อันนี้ จะให้เราใส่คำบรรยายหนังที่เราอยากดู แล้วจะให้คนอื่นมาใส่ว่าหนังอะไร ที่เราควรจะดูที่เข้ากับคำอธิบายที่เราเขียนไป

3rd
Riverdex
ตัวบอกระดับแม่น้ำให้ us ไว้สำหรับคนที่ชอบพายเรือ

รางวัลอื่นๆ

———————————————————————–

RubyMine: A New “Intelligent” Ruby IDE Built on IntellJ

RubyMine เป็น IDE อีกตัวนึงของฝั่ง Ruby/Rails มีครบรองรับทั้ง windows/osx/linux
ใครที่ใช้ IntelliJ IDEA น่าจะคุ้นๆ ดี ดูจากหน้า features แล้ว คิดว่าครบเครืองครับ มี ชุด Testing และ svn ด้วย(แต่ยังไม่มี git นะ)

ใครลองแล้วมา comment feedback กันหน่อยครับ โดยส่วนตัวผมยังอยู่บน textmate/gedit อยู่ดี :p กำลังพยายามไป emacs อยู่

————————————————————————————–

Rails Envy Podcast - Episode #054: 11/05/2008

Subscribe via iTunes - iTunes only link.
Download the podcast ~16:30 mins MP3.
Subscribe to feed via RSS by copying the link to your RSS Reader

Comments 1 Comment »

fragment caching เป็น post ต่อจาก page caching กับ action caching

ชื่อมันก็บอกอยู่แล้วว่าทำ cache แบบเป็นชิ้นๆ สิ่งที่นิยมทำ cache แบบนี้คือการ render เป็นส่วนๆ ในฝั่งของ html template ตัวอย่าง

<b><%= @title %></b>
<% cache do %>
  a lot of text or ruby expression hear and it is
  <%= render :partial => "topic", :locals => {:time => Time.now } %>
<% end %>

ในที่นี้ มันจะ cache ใน block ที่กำหนดไว้ โดยค่า default ในการอ้างถึงจะเป็นชื่อ action และ controller เช่น ถ้าจะ clear cache ก้อนนี้ จะเรียกใช้

expire_fragment(:controller => "topics", :action => "list")

ในความเป็นจริงแล้ว เราอาจจะมี cache หลายที่ในหนึ่งหน้า เลยมี options เพิ่มมา สำหรับกำหนดชื่อให้มันอีก

cache(:action => "list", :action_suffix => "time")

ตัว action_suffix จะเป็นสิ่งที่ทำให้เราสามารถเข้าถึง cache ก้อนนี้ได้ เช่น

expire_fragment(:controller => "topics", :action => "list", :action_suffix => "time") 

แล้วมันเอาไปเก็บไว้ที่ไหน??
จริงๆ ผมเขียนไปในตอนที่แล้วแล้ว ว่ามันเก็บไว้เป็น hash โดยใช้ ActiveSupport::Cache::MemoryStore เป็นตัวบันทึก

รายละเอียดเพิ่มเติมดูได้ใน API ได้เลย

Comments No Comments »

Latest Ruby and Rails Events News: November 2008

ฝรั่งนี่ มันขยันจัดงานจริงๆ

rubyconf2008.png
RubyConf08 - November 6-8, 2008 - Orlando, FL, USA

nwrug.png

North West Ruby User Group Pub Meet - November 20, 2008 - Manchester, UK

americas-wang.png

acts_as_conference 2009 - February 6 & 7, 2009 - Orlando, Florida, USA

atlmerbday.png

Atlanta Merb Day - December 6, 2008 - Atlanta, Georgia, USA

vtmpr.png
Voices That Matter: Professional Ruby Conference - November 17-20, 2008 - Boston, MA, USA

rubyfunday.pngRuby Fun Day - November 22, 2008 - Sector 59, Noida, New Delhi, India

—————————————————————————————————————————-

Mike Gunderloy: Rails Guides Wants You

ทีม Rails กำลังจัดทำ docs ขึ้นมาใหม่ แต่ดูแล้วแค่คนในทีม คงจะเขียนกันอีกนาน กว่าจะเสร็จก็คงมีเวอร์ชันอื่นๆ ออกมาแล้ว เลยใช้มุขแบบ web 2.0 ซะเลย ให้คนมีส่วนร่วม เปิดให้ผู้ใช้งานได้มีโอกาสมาช่วยกันเขียน ใครสนใจตาม link ไปเลยครับ

————————————————————————————————————————–

Episode 134: Paperclip

จากการได้ลองมาแล้ว คิดว่าตัวนี้แหละ ดูเข้าท่าที่สุด เพราะ plugin หลายๆ ตัวทีเคยใช้ มันยังต้องใช้ rmagick แต่ตัวนี้ ไม่ต้อง

Original video source

Comments No Comments »