Pages

2011年9月24日土曜日

rvm で ruby 1.9.2 + Rails3 を実現

そろそろRails3をやらなければ、と思っているうちに Version 3.1になっていた。
Rails3を渋っていた理由は様々あるが、大きいのは ruby 1.9。ruby 1.9は後方互換が結構厳しい。
Rails自身はRubygemsでしっかり管理されていて他のバージョンとの共存が可能だが、rubyは難しいと躊躇していたら、なんと rvmなるものがあるではないか。
rvm -- ruby version manager. 様々なrubyを切り替えて利用することができる
詳しくはここ。
http://beginrescueend.com/rvm/

gemでインストールする方法もあるが、今回狙っている環境は
* さくらVPS
* 特定の開発ユーザだけが、ruby 1.9を使う。通常は 1.8.7
* gem も同様
* virtual hostを利用して、1.9ベースのWebApplicationと1.8.7(rails2)を共存させる
よって、rvmサイトの指示(single user)通り、ソースからインストールすることにした。
http://beginrescueend.com/rvm/install/

rvm インストール

開発用ユーザを追加し、切り替わって
# ソースからインストール (curlが必要)
$ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
# bash_profileに環境を追加
$ echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
$ source ~/.bashrc
# インストール出来たかテスト "rvm is a function"と表示されれば、OK 
$ type rvm | head -1
rvm is a function
それにしても、スクリプトの作成が素晴らしい。これぐらい、さらさら書きたいものだ。
ruby 1.9.2 をインストールしてみる。
$ rvm install 1.9.2
$ ruby -v
ruby 1.8.7 (2010-08-16 patchlevel 302) [x86_64-linux]
$ rvm use 1.9.2  # 切り替える
Using /home/bokunenjin/.rvm/gems/ruby-1.9.2-p290
$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
なるほど。ruby1.9 以外に、yaml rubygems もインストールさせるのか。
rvm use xxxx で他のrubyに切り替え。OSに導入している1.8.7が初期なので、ログアウトすると元に戻る。いつも1.9.2を使いたい場合は $ rvm use 1.9.2 --default でOK。


Rail3を試す

ruby 1.9.2 環境が用意できたので、早速 Rails3をインストール。
gemコマンドの実行は、カレントユーザで行う。(sudoしない。)

 $ gem update
 $ gem install rails
 $ rais new NewApp   # このあたりから、もう違う :-p
 Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem
is installed.
 $ cd NewApp
 $ rails server
プロジェクト作成時点でも、必要なgemが bundleの形で追加インストールされるのか。

sqlite3_native.so: undefined symbol エラー

sqlite3のプロジェクトを作成したときに、以下のようなエラーが出た。
sqlite3_native.so: undefined symbol: sqlite3_initialize
調べてみると、LD_LIBRARY_PATHの問題だととのことで、以下を.bashrcファイル等に追加。
LD_LIBRARY_PATH=/usr/local/lib
export LD_LIBRARY_PATH

Rails3 (3.1.0) 気になること

* JavaScript runtimeにNode.js(V8)が使われている。
* 今回は ActiveResorceを使いこなしてみたい
* すこし、軽くなったような気がする
* MiddlewareのRackについて、詳細を知りたい
* 謎のファイル config.ru , Gemfile (Gemfile.lock)

Casein3のインストール

私は、最近のRails開発では、caseinばかり使っている。caseinは、コンパクトな CMSで、認証機能や管理者画面と、ちょっと小粋なscaffoldを持っているため開発の土台として、とても重宝している。

Rails3の場合は、専用のgemがあるので試したみた。
手順だけ、さっと書く。詳細は https://github.com/spoiledmilk/casein3をみてください。

 $ cd NewApp/
 $ vim Gemfile    # gem "casein" を追加
 $ bundle install  # caseinが必要とするgemはすべて、ここで入る。sudoしない。rvm配下なので。
 $ vim config/initializers/setup_mail.rb    # ユーザ管理用のメールを送る設定
 $ rails g casein:install       # g = generate ?
 $ rails g casein:update     # public/casein内に必要なcss, javascriptなどが配置される
 $ rake db:migrate             # ユーザ管理テーブル作成
 $ rake casein:users:create_admin email=xxxxxxxxx  # 管理者ユーザ登録
 $ rails server -d
見た目は、あんまり変わらないなあ。

2011年9月18日日曜日

CodeIgniter + Dx Auth(認証)+ PostgreSQL

CodeIgniterを使うことになった。
いろいろ、理由があって、データベースはPostgreSQL。
認証ライブラリを試してみる。いろいろなサイトで見た感じでは、Dx_Authが良いらしいので、以下の環境で構築した。

* CentOS 5.5 (final)
* PHP 5.3.8
* CodeIgniter 2.0.3
* Dx_Auth
* PostgreSQL 8.1

実際の作業は試行錯誤の連続だったのだが、記録なのでサクッと書いておく。

Postgresqlをインストール

PHPはremiリポジトリを使って最新バージョン5.3.8をインストールしたため、ドライバも対応したものをremiを使ってインストール。
# yum install postgresql-server.x86_64 postgresql-contrib.x86_64 postgresql-devel.x86_64
# yum install php-pgsql.x86_64 --enablerepo=remi
# /etc/init.d/httpd restart
# テスト用のデータベースも作成
[root@] su - postgres
-bash-3.2$ createdb -E UNICODE -O testman -U postgres cidb

CodeIgniter 2.x

CodeIgniterは、codeigniter 2.0.3 と 日本語パッケージ を導入した。
基本的にはダウンロードして、解凍して、ドキュメントルートに持ってきて、設定を少しいじるだけ。簡単なので、以下を参考してください。
http://codeigniter.jp/

Dx Authのインストール

ここを参考に
http://dexcell.shinsengumiteam.com/dx_auth/

ソースは、CodeIgniter 1.7 で検証されているそうだが、CodeIgniterは、2.xになっていろいろと変わった。修正の方法は、以下のサイトを参考にさせていただいた。
http://d.hatena.ne.jp/ozawa34/20091223/1261581994
日本語化やCI 2.x系の修正済みソースを提供されている方もいらしたので参考に
http://d.hatena.ne.jp/ozawa34/20091223/1261581994

PostgreSQL用にスキーマを変更

MySQLで試すと、あっさりと動作したので、いよいよPostgreSQLへ。
application/config/database.php のドライバ設定部分を"postgre"に変更。
//$db['default']['dbdriver'] = 'mysql';
$db['default']['dbdriver'] = 'postgre';

schema.sqlがDxAuthについているが、もちろんPostgreSQLでは、使えません。
フォーラムの以下のスレッドを参考に、PostgreSQL用のスキーマ作成SQL文をつくってみました。
http://codeigniter.com/forums/viewthread/186278/

-- --------------------------------------------------------

--
-- Table structure for table ci_sessions
--
 
CREATE TABLE ci_sessions (
  session_id varchar(40)  NOT NULL DEFAULT '0',
  ip_address varchar(16)  NOT NULL DEFAULT '0',
  user_agent varchar(150)  NOT NULL,
  last_activity integer NOT NULL DEFAULT '0',
  user_data text,
  PRIMARY KEY (session_id)
);
 
-- --------------------------------------------------------
 
--
-- Table structure for table login_attempts
--
 
CREATE TABLE login_attempts (
  id serial,
  ip_address varchar(40)  NOT NULL,
  time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  primary key(id)
);

-- --------------------------------------------------------

--
-- roles
--

create table roles(
	id serial,
	parent_id integer not null default '0',
	name varchar(30) not null,
	primary key(id)
);

INSERT INTO roles (parent_id, name) VALUES(0, 'User');
INSERT INTO roles (parent_id, name) VALUES(0, 'Admin');

-- --------------------------------------------------------

-- 
-- persissions
--

create table permissions(
	id	serial,
	role_id integer not null,
	data text,
	primary key(id)
);

-- --------------------------------------------------------
 
--
-- Table structure for table user_autologin
--
 
CREATE TABLE user_autologin (
  key_id char(32)  NOT NULL,
  user_id integer NOT NULL DEFAULT '0',
  user_agent varchar(150)  NOT NULL,
  last_ip varchar(40)  NOT NULL,
  last_login timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (key_id,user_id)
);
 
-- --------------------------------------------------------
 
--
-- Table structure for table user_profiles
--
 
CREATE TABLE user_profile (
  id serial,
  user_id integer NOT NULL,
  country varchar(20)  DEFAULT NULL,
  website varchar(255)  DEFAULT NULL,
  primary key(id)
);
 
-- --------------------------------------------------------
 
--
-- Table structure for table users
--
 
CREATE TABLE users (
  id serial,
  role_id integer not null default '1',
  username varchar(25)  NOT NULL,
  password varchar(34)  NOT NULL,
  email varchar(100)  NOT NULL,
  activated smallint NOT NULL DEFAULT '1',
  banned smallint NOT NULL DEFAULT '0',
  ban_reason varchar(255)  DEFAULT NULL,
  newpass varchar(34) default null,
  newpass_key varchar(32) default null,
  newpass_time timestamp DEFAULT CURRENT_TIMESTAMP,
  last_ip varchar(40)  NOT NULL,
  last_login timestamp DEFAULT CURRENT_TIMESTAMP,
  created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  modified timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  primary key(id)
);

-- --------------------------------------------------------

-- 
-- user_temp
--

create table user_temp (
	id serial,
	username varchar(255) not null,
	password varchar(34) not null,
	email varchar(100) not null,
	activation_key varchar(50) not null,
	last_ip varchar(40)  NOT NULL,
  created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  primary key(id)
);

-- --------------------------------------------------------
 
--
-- Update datetime columns on update
--
 
CREATE OR REPLACE FUNCTION update_modified_column_time()
    RETURNS TRIGGER AS $$
    BEGIN
       NEW.time = now(); 
       RETURN NEW;
    END;
    $$ LANGUAGE 'plpgsql';
 
CREATE TRIGGER update_login_attempts_time BEFORE UPDATE
    ON login_attempts FOR EACH ROW EXECUTE PROCEDURE 
    update_modified_column_time();
 
CREATE OR REPLACE FUNCTION update_modified_column_user_autologin()
    RETURNS TRIGGER AS $$
    BEGIN
       NEW.last_login = now(); 
       RETURN NEW;
    END;
    $$ LANGUAGE 'plpgsql';
 
CREATE TRIGGER update_login_attempts_user_autologin BEFORE UPDATE
    ON user_autologin FOR EACH ROW EXECUTE PROCEDURE 
    update_modified_column_user_autologin();
 
 
CREATE OR REPLACE FUNCTION update_modified_column_users()
    RETURNS TRIGGER AS $$
    BEGIN
       NEW.modified = now(); 
       RETURN NEW;
    END;
    $$ LANGUAGE 'plpgsql';
 
CREATE TRIGGER update_login_attempts_users BEFORE UPDATE
    ON users FOR EACH ROW EXECUTE PROCEDURE 
    update_modified_column_users();

-- -----------------------------------------------------------------
-- no params
CREATE OR REPLACE FUNCTION unix_timestamp() RETURNS BIGINT AS '
	SELECT EXTRACT(EPOCH FROM CURRENT_TIMESTAMP(0))::bigint AS result;
' LANGUAGE 'SQL';
 
-- timestamp without time zone (i.e. 1973-11-29 21:33:09)
CREATE OR REPLACE FUNCTION unix_timestamp(TIMESTAMP) RETURNS BIGINT AS '
	SELECT EXTRACT(EPOCH FROM $1)::bigint AS result;
' LANGUAGE 'SQL';
 
-- timestamp with time zone (i.e. 1973-11-29 21:33:09+01)
CREATE OR REPLACE FUNCTION unix_timestamp(TIMESTAMP WITH TIME zone) RETURNS BIGINT AS '
	SELECT EXTRACT(EPOCH FROM $1)::bigint AS result;
' LANGUAGE 'SQL';


その他

最初にMySQLで試したのだが、その時の記録

MySQL。使わない、使えないユーザは消した。そしてDxAuthに必要なテーブルの一覧。
mysql> delete from user where user = '';
mysql> grant select,insert,update,delete,create,drop on cidb.* to miyabiman;
Query OK, 0 rows affected (0.06 sec)

[baker@www dx_auth]
$ mysql -u miyabiman -h localhost cidb -p  < schema.sql

mysql> show tables;
+----------------+
| Tables_in_cidb |
+----------------+
| ci_sessions    |
| login_attempts |
| permissions    |
| roles          |
| user_autologin |
| user_profile   |
| user_temp      |
| users          |
+----------------+
8 rows in set (0.00 sec)

作業の過程でつまずいたことなど。メモとして。
  • ログが書き込みされない
  • Session key 作成
  • PL/PGSQLが必要 # create language plpgsql;
  • テーブルが足りない
  • Primary Keyを用意する

2011年9月4日日曜日

Titaniumでバーコードライブラリを使う

検討中のiPhoneアプリの現在の課題はバーコード。(少しづつ、少しづつ進んでます)
Tituniumで利用できるiPhone用のバーコードライブラリは、TiBarが一番手のようだ。
TiBar -- ZBar integration module for Titanium Mobile.
と言うことで、ZBarライブラリをTitaniumで利用出来るようにしたものらしい。 http://code.google.com/p/tibar/

ZBarライブラリについては、ここ http://zbar.sourceforge.net/
ZBar is an open source software suite for reading bar codes from various sources, such as video streams, image files and raw intensity sensors. It supports many popular symbologies (types of bar codes) including EAN-13/UPC-A, UPC-E, EAN-8, Code 128, Code 39, Interleaved 2 of 5 and QR Code.

インストール

1. 最新版をダウンロード (2011.9.4 現在 0.4.2)
2. 解凍したモジュールを以下にコピー。
$ cp -r modules/iphone/tibar /Library/Application\ Support/Titanium/modules/iphone/
3. (プロジェクトに未登録のフレームワークを) Xcodeのプロジェクトファイルに追加する
  • AVFoundation.framework 
  • CoreMedia.framework
  • CoreVideo.framework
  • QuartzCore.framework
  • libiconv.dylib 
さらっと、書いたけど、これは一寸面倒。 
  1. /Library/Application Support/Titanium/mobilesdk/osx/1.7.2/iphone/iphone/Titanium.xcodeproj ファイルを起動し(Xcodeでファイルが開く)
  2. [Bundle Phases]タブを選び
  3. 右下にある [Link Binary with Libraries]ボタンにてライブラリリストを展開
  4. 上記のフレームワークを追加(Link)していくのだ。(選んで、追加ボタンを実施)

参考にさせてもらったのは、このサイト。 http://zaru.tofu-kun.org/2011/08/11/iphoneでバーコードをスキャンしたい!titanium-mobileでzbarを使う/

どうやら、このファイルをコピーして、初期プロジェクトファイルを作成していくらしい。
今回のコードは、既存のプロジェクトに追加したため、最初はmodule tibarの読み込みに失敗した。
再度、きれいにBuildする必要があった。
http://code.google.com/p/tibar/issues/detail?id=10

Tibarライブラリを使う

tiapp.xml プロジェクト定義ファイルに、モジュール追加記述
<modules>
 <module version="0.4.2">tibar</module>
</modules>
そして、requireする。 var TiBar = require('tibar');
var TiBar = require('tibar');  // TiBarモジュールの読み込み

// Window, Label, Button を用意
var win = Ti.UI.currentWindow;
var label = Ti.UI.createLabel({
	color:'#999',
	text:'this is scan windows.',
	font:{fontSize:20,fontFamily:'Helvetica Neue'},
	textAlign:'center',
	top:10,
	height:30
});
win.add(label);
var scanButton = Ti.UI.createButton({
	title:'Scan It',
	top:80,
	left:10,
	width:300,
	height:100
});
win.add(scanButton);

// clickイベントの中にスキャン動作を定義
scanButton.addEventListener('click', function(){
	TiBar.scan({
		// 設定パラメータ (JSON形式)
		configure: {
			// ZBarReaderViewController(VC), ZBarReaderController ( C )  の2種
			classType: "ZBarReaderViewController",
			// Library ( C ), Album ( C ), Camera ( VC ) の 3種
			sourceType: "Camera",
			// Default , Sampling , Sequence
			cameraMode: "Default",
			config:{
				"showsCameraControls":true,
				"showsZBarControls":true,
				"tracksSymbols":true, // スキャンする時に四角の枠を表示する
				//"showsSymbols":true,
				"enableCache":true,
				"showsHelpOnFail":true,
				"takesPicture":false
			},
			// この他、Symbol 設定で利用可能なバーコードを決められる
		},
		
		// 成功した場合の処理定義
		success:function(data){
			Ti.API.info('TiBar success callback!');
			if(data && data.barcode){
				Ti.UI.createAlertDialog({
					title: "Scan Result",
					message: "Barcode: " + data.barcode + 'Symbology:' + data.symbology
				}).show();
			};
		},
		// 中止した時の処理定義
		cancel:function(){
			Ti.API.info("TiBar cancel callback!");
		},
		// エラーを起こした場合の定義
		error:function(){
			Ti.API.info("TiBar error callback!");
		}
	});
});
処理の分岐を、JSON形式で書いていくのは、なんか関数型言語のような感じで面白い。
実行したら、カメラシミュレータの画面が出た。iPhoneシミュレータなので、これでおしまいのようだ。
TiBarのサイトには、シミュレータでバーコード処理を再現するための方法も書いてあったが、なんかハマりそうだったので、今回はこれで満足。