XREA で ruby on rails のアプリを公開する

XREArails のアプリを

http://mydomain/***/controller

という URL で公開しようと思ったら、
意外と大変だったので、ポイントをメモしておきます。

もっと簡単で綺麗な方法があるかと思いますが、
ここでは「とりあえず動かして公開」することを目的としています。

動作しているところ

http://gachapin.jp/todo/tasks


自分の環境

rubygems のインストール

http://d.hatena.ne.jp/critbit/20080522/1211487953

を参考にしてインストール。

環境変数は上記 URL 先と同じように

PREFIX=$HOME
export PATH=$PREFIX/bin:$PREFIX/lib/ruby/gems/1.8/bin:$PATH
export GEM_HOME=$PREFIX/lib/ruby/gems/1.8
export RUBYLIB=$PREFIX/lib/ruby:$PREFIX/lib/site_ruby/1.8:$PREFIX/lib

ここでインストールした gem のバージョンは 1.3.3 。

gem -v

1.3.3

rails のインストール

gem install rails -v 2.2.2 --no-ri --no-rdoc

Successfully installed rake-0.8.6
Successfully installed activesupport-2.2.2
Successfully installed activerecord-2.2.2
Successfully installed actionpack-2.2.2
Successfully installed actionmailer-2.2.2
Successfully installed activeresource-2.2.2
Successfully installed rails-2.2.2
7 gems installed

ここでのポイント

  • --no-ri, --no-rdoc はインストールする時間を削減するため
    • XREA では時間がかかるプロセスは kill されてしまう
  • なぜかインストールに失敗することがある
    • もう一度実行すると成功したりする
  • rails の version は 2.2.2 を入れた ← 重要ポイント
    • XREA では dispatch.cgirails を実行するのに必要らしい ( ? )
      • 2.3.2 では dispatch.cgi がデフォルトでは生成されない
        • dispatch.cgi を生成するオプションをつけて実行しても、少なくとも自分の環境では正しく動かなかった

アプリの作成 ( サーバ側で作成編 )

サーバ内でコマンドを叩いてアプリを作る。

$home ディレクトリ下に アプリを作成。
DB は sqlite3 を使用。簡単だから。

作る物は http://d.hatena.ne.jp/koumiya/20080831/1220164527 を参考にした。

cd $home
rails todo -d sqlite3
cd todo
ruby script/generate scaffold task title:string
rake db:migrate RAILS_ENV=production

続いて dispatch.cgi の修正。

cd public
vi dispatch.cgi

dispatch.cgi の 1 行目を以下のように変更。

#!/usr/bin/env ruby

続いて public ディレクトリ下に .htaccess を作成した。

vi .htaccess

こんな内容に。

Options +FollowSymLinks +ExecCGI
AddHandler cgi-script .cgi
RewriteEngine On
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]

SetEnv RAILS_ENV production
SetEnv GEM_HOME /virtual/gachapin/lib/ruby/gems/1.8
SetEnv RUBYLIB /virtual/gachapin/lib/ruby:/virtual/gachapin/lib/site_ruby/1.8:/virtual/gachapin/lib

重要ポイント。config/routes.rb を編集。

vi ../config/routes.rb

path_prefix を設定。
コメントを除くとこんな感じ。

ActionController::Routing::Routes.draw do |map|
  path_prefix = :todo
  map.resources :tasks, :path_prefix => path_prefix

  map.connect ':controller/:action/:id', :path_prefix => path_prefix
  map.connect ':controller/:action/:id.:format', :path_prefix => path_prefix
end

これで設定は完了。
後は $home/public_html ディレクトリ下から rails のアプリ公開ディレクトリにシンボリックリンクをはるだけ。

cd $home
cd public_html
ln -s ../todo/public todo

完成。

http://gachapin.jp/todo/tasks

アプリの作成 ( ローカルで作成してからアップロード編 )

サーバでコマンドを叩くのとほとんど一緒。

シンボリックリンクをはる前まで終わったら、todo を圧縮。

tar -cvzf todo.tgz todo

scp やら sftp やらでサーバにアップロード

scp todo.tgz gachapin@???.xrea.com:
password :

サーバにログイン後、解凍

tar -xvzf todo.tgz

そしたら、サーバ側で作成編と同じようにシンボリックリンクをはって完了。

cd public_html
ln -s ../todo/public todo

todo 全部をアップロードしなくても OK だとは思うけど。

携帯からの使用について

携帯からの使用の場合、以下の二つの問題があった

  1. create, update ( destroy ) で 422 エラー
  2. destroy が動作しない
1. create, update ( destroy ) で 422 エラー について

InvalidAuthenticityToken により 422 エラーとなってしまう。うまくトークンが渡っていない模様。トークンはセッションでやり取りをしているのだろうか?

てっとり早い対策として、CRF 対策を無効化してしまえばよい。http://d.hatena.ne.jp/crimaru/20080819/1219128042 あたりを参考に skip_before_filter を設定すれば 422 エラーは消えて、携帯からも使えるようになる。しかし CRF への対策は当然のことながらなくなってしまう。もっと良い方法はないものか。

ところで、これの原因は XREArails どちらなのだろう。

2. destroy が動作しない について

こちらは rails の問題。

デフォルトでは

  • destroy は HTTP の delete メソッドで動作する
  • index.html.erb から Destroy へのリンクが javascript となっている。さらに delete メソッドのリンクとなっている

という設定になっているのだが、携帯は delete メソッド、javascript に対応していない ( 最新の携帯なら対応してたりするのかも?? ) ので、これらを対処する必要がある。

destroy を get メソッドで動作させるために config/routes.rb を編集する。上のほうで

  map.resources :tasks, :path_prefix => path_prefix

と変更していたところを

  map.resources :tasks, :member => { :destroy => :get }, :path_prefix => path_prefix

とさらに修正する。これで destory が get メソッドで動作するようになる。


そして次に、index.heml 等から destroy へのリンクが tasks/id/destroy を指すようにする。app/views/tasks/index.html.erb などの

<td><%= link_to 'Destroy', task, :confirm => 'Are you sure?', :method => :delete %></td>

<td><%= link_to 'Destroy', :controller => 'tasks', :action => 'destroy', :id => task %></td>

と変更する。これで Destroy のリンクが 目的の URL を指すようになる。

link_to ( というか、内部で読んでいる url_for ) は config/routes.rb を参照して URL を生成するので、config/routes.rb を正しく変更しないと目的の URL を吐いてくれないので注意。

しかし、GET メソッドで削除ってのは気持ち悪いので、せめて POST メソッド + form を使った方が良いと思うが、それについてはいずれ。

TODO

  • controllers/application.rb で before_filter :basic_authentication を設定してみたが、認証できない
  • .htaccess をもっと適切なものに書き直す
  • ローカルでアプリを作成する場合 rake rails:freeze:gems を使えばサーバ側に rails をインストールする必要はない??

注意

  • サーバの種類 ( s???.xrea.com ) によっては上記で動かないかもしれません