[Ruby] ActiveRecord off Rails

» Posted by on Jan 8, 2009 in Blog | 0 comments

How to use ActiveRecord without Rails.

Memo

  • Usually no need to write definition of database tables.
    Just define sub class of ActiveRecord::Base.
    ActiveRecord automatically checks table definition at the first access.
  • Better to use ActiveRecord’s naming rules
    If name tables or fields without the naming rules, should add extra code into sub class of ActiveRecord::Base
  • Need to write SQL directory when do complicated stuff.
  • Access to table with sub class instance of ActiveRecord::Base

Basic Usage

  1. Create database configuration YAML file
  2. Create a sub class of ActiveRecord::Base for each table
  3. Establish connection with the YAML file.
  4. Do something with the sub class of ActiveRecord::Base

Simple Usage

#!/usr/bin/env ruby

# definition of 'groups' table
#CREATE TABLE IF NOT EXISTS groups (
#  id       INT(32) UNSIGNED NOT NULL AUTO_INCREMENT,
#  name     VARCHAR(255) NOT NULL,
#  PRIMARY KEY (id)
#) ENGINE=MyISAM;

require 'rubygems'
require 'activerecord'

# automatically map to 'groups' table.
class Group < ActiveRecord::Base
end # class

spec = {
  :adapter  => 'mysql',
  :encoding => 'utf8',
  :database => 'messadb_dev', # database name
  :username => 'messauser',   # username for mysql
  :password => 'messapass',   # password for mysql
  :socket   => '/var/run/mysqld/mysqld.sock',
}
ActiveRecord::Base.establish_connection(spec)

# create a record
group = Group.new
#group.id = 2
group.name = 'christmas town'
group.save

# find a record by it's name
group = Group.find_by_name('christmas town')
puts "group.id   : #{group.id}"   # 
puts "group.name : #{group.name}" # 'christmas town'

Sample Environment

database: mysql
dbnames:
  for production:  messadb
  for test:        messadb_test
  for development: messadb_dev
tables:
  table1: users
  table2: groups

Sample Directory Structure

activerecord-sample/
  app/
    messa_app.rb      # main program
  config/
    database.yml      # configuration file for database connection
  db/
    setup_dev.mysql   # script for initializing database
  lib/
    messa/
      db.rb           # Messa::DB::Base, a sub class of ActiveRecord::Base
      db/
        user.rb      # a sub class of Messa::DB::Base
        group.rb     # a sub class of Messa::DB::Base

Install requirements (Ubuntu 8.10 Intrepid Ibex)

% sudo aptitude install ruby rubygems
% sudo gem install activerecord
% sudo aptitude install libmysql-ruby

Setup and execute

% cd activerecord-sample
% mysql -u root -p
mysql> source db/setup_dev.mysql
mysql> exit
% ruby app/messa_app.rb

app/messa_app.rb

load Messa::DB::User and Messa::DB::Group sub classes of ActiveRecord::Base.

require 'messa/db'
require 'messa/db/user'
require 'messa/db/group'

load a YAML database configuration file, then set it to Messa::DB::Base and select configuration for development.

config_file = File.join(MESSA_CONFIG_DIR, 'database.yml')
config = YAML::load(ERB.new(IO.read(config_file)).result)
Messa::DB::Base.configurations = config
Messa::DB::Base.establish_connection(:messadb_development)
#Messa::DB::Base.establish_connection(:messadb_test)
#Messa::DB::Base.establish_connection(:messadb_production)

create a new group and save.

group = Messa::DB::Group.new
group.id = 1
group.name = 'halloween town'
group.save

create a new user and save.

user = Messa::DB::User.new
user.id   = 1
user.group_id   = 1
user.name = 'Jack'
user.birthday  = '1901-10-31'
user.save

find a user by id then print values.

jack = Messa::DB::User.find(1)
puts "jack.id         : #{jack.id}"         # 1
puts "jack.group_id   : #{jack.group_id}"   # 1
puts "jack.group.name : #{jack.group.name}" # 'halloween town'
puts "jack.name       : #{jack.name}"       # 'Jack'
puts "jack.birthday   : #{jack.birthday}"   # '19001-10-31'
puts "jack.age        : #{jack.age}"        # 107


Source Code

Download Source Code

messa_app.rb
#/usr/bin/env ruby
# -*- coding: utf-8 -*-

$LOAD_PATH << File.expand_path(File.join('..', 'lib'), File.dirname(__FILE__))

require 'messa/db'
require 'messa/db/user'
require 'messa/db/group'
require 'date'

MESSA_ROOT_DIR   = File.expand_path(File.join('..'), File.dirname(__FILE__)) unless defined? MESSA_ROOT_DIR
MESSA_CONFIG_DIR = File.join(MESSA_ROOT_DIR, 'config')                       unless defined? MESSA_CONFIG_DIR

config_file = File.join(MESSA_CONFIG_DIR, 'database.yml')
config = YAML::load(ERB.new(IO.read(config_file)).result)
Messa::DB::Base.configurations = config
Messa::DB::Base.establish_connection(:messadb_development)
#Messa::DB::Base.establish_connection(:messadb_test)
#Messa::DB::Base.establish_connection(:messadb_production)

Messa::DB::Group.delete_all
Messa::DB::User.delete_all

group = Messa::DB::Group.new
group.id = 1
group.name = 'halloween town'
group.save

user = Messa::DB::User.new
user.id   = 1
user.group_id   = 1
user.name = 'Jack'
user.birthday  = '1901-10-31'
user.save

user = Messa::DB::User.new
#user.id   = 2
user.group_id   = 1
user.name = 'Sarry'
user.birthday  = '1997-10-31'
user.save

puts "today : #{Date.today}" # 2009-01-06

jack = Messa::DB::User.find(1)
puts "jack.id         : #{jack.id}"         # 1
puts "jack.group_id   : #{jack.group_id}"   # 1
puts "jack.group.name : #{jack.group.name}" # 'halloween town'
puts "jack.name       : #{jack.name}"       # 'Jack'
puts "jack.birthday   : #{jack.birthday}"   # '19001-10-31'
puts "jack.age        : #{jack.age}"        # 107

sarry = Messa::DB::User.find(:first, :conditions => {:name => 'Sarry'})
puts "sarry.id         : #{sarry.id}"        # 
puts "sarry.group_id   : #{sarry.group_id}"  # 1
puts "sarry.group.name : #{jack.group.name}" # 'halloween town'
puts "sarry.name       : #{sarry.name}"      # 'Sarry'
puts "sarry.birthday   : #{sarry.birthday}"  # '1997-10-31'
puts "sarry.age        : #{sarry.age}"       # 11

__END__

today : 2009-01-06
jack.id         : 1
jack.group_id   : 1
jack.group.name : halloween town
jack.name       : Jack
jack.birthday   : 1901-10-31
jack.age        : 107
sarry.id         : 10
sarry.group_id   : 1
sarry.group.name : halloween town
sarry.name       : Sarry
sarry.birthday   : 1997-10-31
sarry.age        : 11
database.yml
messadb_development:
  adapter: mysql
  encoding: utf8
  database: messadb_dev
  username: messauser
  password: messapass
  socket: /var/run/mysqld/mysqld.sock

messadb_test:
  adapter: mysql
  encoding: utf8
  database: messadb_test

  username: messauser
  password: messapass
  socket: /var/run/mysqld/mysqld.sock

messadb_production:
  adapter: mysql
  encoding: utf8
  database: messadb
  username: messauser
  password: messapass
  socket: /var/run/mysqld/mysqld.sock
setup_dev.mysql
-- messadb

-- % mysql -u root -p
-- mysql> create database messadb;
-- mysql> source create_tables.mysql
-- mysql> exit

DROP DATABASE messadb_dev;

CREATE DATABASE IF NOT EXISTS messadb_dev DEFAULT CHARACTER SET utf8;
GRANT ALL PRIVILEGES ON messadb_dev.* TO messauser@localhost IDENTIFIED BY 'messapass';

use messadb_dev;

CREATE TABLE IF NOT EXISTS users (
  id       INT(32) UNSIGNED NOT NULL AUTO_INCREMENT,
  group_id INT(32) UNSIGNED NOT NULL,
  name     VARCHAR(255) NOT NULL,
  birthday DATE         NULL,
  added             TIMESTAMP    NOT NULL DEFAULT 0,
  updated           TIMESTAMP    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
) ENGINE=MyISAM;

CREATE TABLE IF NOT EXISTS groups (
  id       INT(32) UNSIGNED NOT NULL AUTO_INCREMENT,
  name     VARCHAR(255) NOT NULL,
  added             TIMESTAMP    NOT NULL DEFAULT 0,
  updated           TIMESTAMP    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
) ENGINE=MyISAM;
db.rb
# -*- coding: utf-8 -*-

require 'rubygems'
require 'activerecord'
require 'erb'
require 'yaml'

module Messa
  module DB
    class Base < ActiveRecord::Base
    end # class
  end # module
end # module
users.rb
# -*- coding: utf-8 -*-

require 'messa/db'
require 'date'

module Messa
  module DB
    class User < Messa::DB::Base
      set_table_name 'users'
      #has_one :group, {:class_name => 'Messa::DB::Group', :foreign_key => 'id'} # this works
      has_one :group, {:class_name => 'Messa::DB::Group', :foreign_key => 'id', :primary_key => 'group_id'}

      def age
        birthday = read_attribute(:birthday)
        return nil if birthday.nil?

        today = Date.today
        age = today.year - birthday.year
        if (today.month < birthday.month) or (birthday.month == today.month and today.day < birthday.day)
          age -= 1
        end
        return age
      end

      def age=(rhs)
        raise "Can't set value to age."
      end
    end # class
  end # module
end # module
groups.rb
# -*- coding: utf-8 -*-

require 'messa/db'

module Messa
  module DB
    class Group < Messa::DB::Base
      set_table_name 'groups'
    end # class
  end # module
end # module