Less talk, more code

The blog of Iskandar Soesman

Membuat Web Framework Sendiri Menggunakan Ruby

Belakangan saya sedang mencari tutorial membuat aplikasi web menggunakan bahasa pemrogramman Ruby namun tanpa framework apapun. Dari hasil pencarian di Google hasilnya kurang memuaskan. Sebagian besar tutorial mengajarkan menggunakan Rails. Tidak heran hasil pencarian menunjukan demikian mengingat Ruby on Rails adalah framework yang sangat populer. Rails ataupun framework yang lainnya adalah bagus. Namun ketika kita bisa membuat aplikasi dari dasar tanpa menggunakan framework apapun, akan lebih mudah untuk kemudian menggunakan framework manapun. Hal ini lah yang kemudian mendorong saya membuat tulisan ini.

Dari beberapa referensi yang terkumpul, saya akan coba buat dalam satu tutorial dengan harapan akan memudahkan teman-teman developer yang ingin membuat aplikasi web menggunakan Ruby dari nol. Dalam tutorial ini saya menggunakan sistem operasi Ubuntu. Silahkan sesuaikan dengan kondisi OS yang Anda gunakan.

Semua modul dalam tutorial ini sudah tersedia dalam instalasi Ruby jika Anda menginstal dengan lengkap. Modul-modul yang dibutuhkan selain core Ruby adalah rack untuk web server development dan erb untuk templating, serta cgi.

Instalasi

Untuk instalasi paket full Ruby di Ubuntu silahkan ketikan perintah:

sudo apt-get install ruby-full

Untuk memastikan Ruby sudah terinstall dengan baik silahkan ketik:

ruby -v

Kemudian ketikkan perintah di bawah ini untuk memastikan modul rack tersedia:

rackup -v

Jika semuanya tidak ada masalah, sekarang waktunya untuk memulai pembuatan aplikasi. Agar aplikasi kita mudah untuk dideploy di server production yang umumnya menggunakan Passanger baik itu di Apache maupun di Nginx, kita akan mengikuti protocol yang disyaratkan oleh Passanger yaitu: buat dua buah folder masing-masing bernama public dan temp dan buat sebuah file bernama config.ru.

Buka file config.ru dan isikan:

class Gear
    def call(env)
        [200, {"Content-Type" => "text/html"}, 'hello world']
    end
end

run Gear.new

Di dalam terminal pindah ke root folder aplikasi Anda dan ketikkan:

rackup config.ru

Buka browser dan masukkan alamat:

http://localhost:9292

Komponen Dasar

Jika berjalan lancar browser akan menampilkan pesan "hello world". Jika bagian ini sudah berhasil, maka selanjutnya adalah membuat komponen pembantu untuk aplikasi. Buka kembali file config.ru dan rubah isinya hingga menjadi seperti berikut:

# Modul erb dibutuhkan untuk templating
# Modul cgi dibutuhkan untuk parsing query string
require 'erb'
require 'cgi'

# Class Constructor akan menjadi parent dari
# setiap halaman controller yang bertugas untuk
# mensuplai segala kebutuhan dari masing-masing controller
class Controller

    def initialize env
        @envs = env
    end

    def view(file, data = false)

        template_string = File.read('views/' + file + '.html')
        template = ERB.new template_string
        return template.result(binding)
    end

    def model file
        require 'models/' + file + '.rb'
        mod = file.capitalize
        Kernel.const_get(mod).new
    end

    def POST
        q = @envs['rack.input'].gets
        self.parse_query q
    end

    def GET
        q = @envs['QUERY_STRING']
        self.parse_query q
    end

    def parse_query string
        CGI.parse(string) # Hash[*string.split(/=|&/)].inspect
    end
end

# Class ini akan dieksekusi pertama kali
# oleh reck webserver
class Gear
    def call(env)

        url = env['PATH_INFO']
        url.slice!(0)

        # Defenisikan nama controller dan method default
        controller = 'home'
        method = 'index'

        # Split url string berdasarkan pemisah '/'
        url_spl = url.split('/')

        # Dapatkan nama controller
        if url_spl.include? url_spl[0]
          controller = url_spl[0]
        end

        # Pastikan apakah file controller tersedia
        if not File.file? 'controllers/' + controller + '.rb'
          return self.error_404('controller not exists')
        end

        url_spl.delete_at(0)

        require 'controllers/' + controller + '.rb'

        # Dapatkan nama method
        if url_spl.include? url_spl[0]
          method = url_spl[0]
          url_spl.delete_at(0)
        end

        # Perbesar huruf pertama dari controller untuk menjadi nama class
        controller = controller.capitalize

        instance = Kernel.const_get(controller).new env

        # Pastikan method tersedia
        if not instance.respond_to? method
          return self.error_404('methond not exists')
        end

        # Semua sudah tersedia, tampilkan isi method

        if url_spl.size > 0
          output_str = instance.method(method).call(*url_spl)
        else
          output_str = instance.method(method).call
        end

        self.output(output_str)
    end

    def error_404(message = '')
        self.output('Page not found! ' + message, 404)
    end

    def output(string, code = 200)
        if (string.nil? or string == 0)
            string = 'output empty'
        end
        [code, {"Content-Type" => "text/html"}, string]
    end
end

run Gear.new

Di atas adalah core sitem MVC sederhana untuk aplikasi kita. Untuk itu kita membutuhkan setidaknya tiga folder baru yang masing-masing kita beri nama models, views dan controllers.

Dengan pola MVC di atas, struktur url website kita menjadi:

http://localhost:9292/nama_controller/nama_method/argumen_1/argumen_2

Contrloller

Masuk ke dalam folder controllers, buat sebuah file baru dan beri nama home.rb yang isinya:

class Home < Controller

  def initialize env
    super env
  end

  def index
    'Ini adalah output dari method index di dalam calss Home'
  end

end

Kemudian akses browser dengan alamat:

http://localhost:9292/home/index

Di sini index adalah method default yang artinya, jika tidak ada argumen setelah nama controller pada url, maka method ini yang akan dieksekusi. Dengan demikian hasil yang sama akan didapat dengan url:

http://localhost:9292/home

Sama halnya dengan index, home juga menjadi nama default untuk nama controller jika tidak ada argumen yang menyebutkan nama controller. Urlnya bisa menjadi:

http://localhost:9292/home

Untuk membuat controller lainnya, Anda cukup membuat sebuah file baru di dalam folder controllers dan buat sebuah class dengan nama yang sama seperti nama file. Contohnya saya akan membuat controller foo, berikut adalah isi dari file foo.rb saya:

class Foo < Controller

  def initialize env
    super env
  end

  def index
    'Ini adalah output dari method index di dalam calss Foo'
  end

  def hello
    'Hello from foo'
  end
end

Kemudian akses browser dengan alamat:

http://localhost:9292/foo

atau:

http://localhost:9292/foo/hello

View

Untuk membuat sebuah template atau view, masuk ke dalam folder vews dan buat sebuah file html, misalnya hello.html yang isinya:

<h3>Nama saya <%= data['name'] %></h3>

Kemudian di dalam controller isikan seperti berikut:

class Foo < Controller
    def initialize env
        super env
    end
    def index
        'Ini adalah output dari method index di dalam calss Foo'
    end
    def hello(name = 'kandar')
        args = {'name' => name}
        self.view('hello', args)
    end 
end

Akses browser dengan alamat:

http://localhost:9292/foo/hello http://localhost:9292/foo/hello/budi http://localhost:9292/foo/hello/jhon

Model

Sama seperti controller, untuk membuat model Anda cukup membuat sebuah file di dalam folder models, dan buat sebuah class dengan nama yang sama dengan nama file. Contohnya: my_data.rb yang isinya:

class My_data

  def samples
    'ini data dari model My_data'
  end

end

Untuk me-load class model ke dalam controller, caranya adalah:

class Foo < Controller

  def initialize env
    super env
    @my_data = self.model 'my_data'
  end

  def index
    'Ini adalah output dari method index di dalam calss Foo'
  end

  def data_from_model
    @my_data.samples
  end

end

Kemudian akses browser:

http://localhost:9292/foo/data_from_model

Class model diperuntukan untuk menangani semua proses yang terkait dengan data. Untuk melakukan koneksi ke database, Anda membutuhkan driver dari database yang akan digunakan. Sebagi contoh saya akan menggunakan mysql maka isi file model saya:

require 'mysql'

class My_data

  def initialize
    @connection = Mysql.new(hostname, username, password, databasename)
  end

  def samples
    @connection.query('SELECT * FROM my_table')
  end

end

Aplikasi selesai. Kini Anda tidak perlu lagi bergantung pada framework apapun untuk membuat aplikasi web menggunakan Ruby, selamat mencoba!