Jekyll は軽快なブログソフトなので乗り換えてみた
今まで EY-Officeホームページ・ブログ は Radiant を使って作成していたが、Jekyll に変更しました。
Radiantは高機能なのですが、Webアプリのため原稿を書き確認するというサイクルが遅いとか、文章を入力するtextareaは貧弱などの問題がありました。
また、EY-Officeホームページ・ブログはradiantからスタティックなページを作成し、サーバーに転送していましたが、これも一手間でした。
Jekyll とは?
Jekyll は ローカル(自分のMac,PC)で動くプログラマー向けのCMS、Blog作成ソフトです。
- ページの原稿は Mac上のエディターで書きファイルに保存します
- jekyllコマンドは、原稿からスタティックな html ファイルが生成します
- また、jekyll コマンドは確認用サーバーにもなり、Mac上で生成されたページが確認できます
- 原稿用のマークアップ言語としては標準で Markdown, Textile, html が使えます
- 一般的なCMS、Blogソフト同様にレイアウト(テーマ)や生成されるページの共通部分をまとめる機能があります
- ページ生成に便利なLiquidテンプレート言語が使えます
- ブログ用の機能も持っています
- 原稿が変更されると、確認サーバーは自動的に html ファイルを更新します(設定によっては)
- 原稿ファイルの管理は git 、コマンドの自動化は rake などの既存ツールを使います
- http://pages.github.com/ で使われます
Jekyll の使い方
インストール
既にRubyがインストールされていれば
% gem install jekyll % gem install RedCloth
だけです。 マークアップに Markdown を使うなら gem install RedCloth は不要です
Jekyll のドキュメント
Jekyllのドキュメントは https://github.com/mojombo/jekyll/wiki にありますが、構成が良くなく以前みたドキュメントが探せなくて困ったので一覧にしておきました。
- 概要: https://github.com/mojombo/jekyll/wiki/usage
- コンフィグの解説: https://github.com/mojombo/jekyll/wiki/configuration
- 原稿ファイル先頭部分の設定: https://github.com/mojombo/jekyll/wiki/yaml-front-matter
- テンプレートから参照できる値など: https://github.com/mojombo/jekyll/wiki/template-data
- ブログのURL生成規則: https://github.com/mojombo/jekyll/wiki/permalinks
- Liquidテンプレートの解説:https://github.com/shopify/liquid/wiki/liquid-for-designers
- Liquidテンプレートの Jekyll独自拡張: https://github.com/mojombo/jekyll/wiki/liquid-extensions
- 独自プラグインの作り方: https://github.com/mojombo/jekyll/wiki/Plugins
作業環境(ディレクトリー)の作成
https://github.com/mojombo/jekyll/wiki/usage にあるようなディレクトリーを準備します。_ から始まるディレクトリー、ファイルが Jekyll 用です。
画像やCSS用ディレクトリーは適当つくれば良いです。
https://github.com/mojombo/jekyll/wiki/sites に Jekyll を使ってるサイトとそのソース(たいていgithub)が公開されているので、いくつかの ソースを clone/ダウンロードして眺めてみるとをお勧めします。
私の環境は以下のようになってます
ekyll-ey-office/ ├── Gemfile ├── _config.yml ← 設定ファイル ├── _includes ← 共通ファイル │ ├── footer.html │ ├── google_analytics.html │ ├── header.html │ └── menu_bar.html ├── _layouts ← レイアウトファイル │ ├── blog.html │ ├── default.html │ └── home.html ├── _plugins ← 独自プラグイン │ └── menu_image.rb ├── _posts ← ブログ原稿ファイル │ ├── 2009-08-31-type-of-cloud.html.textile ... │ ├── 2012-06-11-is-mac-expensive.html.textile │ └── 2012-06-18-paas-service.textile ├── _site ← 生成されたhtml(css,image)が入るディレクトリー │ └── ├── atom.xml ↓ ここからは原稿ファイル ├── blog.textile ├── blog_archive │ └── index.textile ├── company.textile ├── company_development.textile ├── css │ └── base.css ├── education.textile .... ├── images │ ├── ey_logo3.jpg │ ├── flower2.jpg .... │ └── xcode.png ├── index.textile ├── news │ ├── index.textile ... │ └── news-2009.textile └── robots.txt
コマンドの起動
設定ファイルを書き、原稿を準備し(次のセクションで説明します) jekyll を実行すると
% jekyll Configuration from /Users/yy/Documents/jekyll-ey-office/_config.yml Auto-regenerating enabled: /Users/yy/Documents/jekyll-ey-office -> /Users/yy/Documents/jekyll-ey-office/_site [2012-06-20 17:04:20] regeneration: 91 files changed [2012-06-20 17:04:20] INFO WEBrick 1.3.1 [2012-06-20 17:04:20] INFO ruby 1.9.3 (2012-04-20) [x86_64-darwin11.3.0] [2012-06-20 17:04:20] INFO WEBrick::HTTPServer#start: pid=2698 port=4000 [2012-06-20 17:04:47] regeneration: 1 files changed
のように、原稿からhtmlへの変換され、確認用サーバーが起動されます。自動更新にしておくと原稿が変更されると自動的にhtmlに変換されるので ブラウザーをリロードするだけで、最新のコンテンツを確認できます。
確認サーバーの終了は ^C 等で行ってください。
EY-Officeホームページ・ブログの設定例
設定ファイル _config.yml
server: true でjekyll コマンド実行後、http://localhost:4000 に確認用サーバーが立ち上がります。また auto: true なので原稿が更新されると対応するhtmlが自動的に更新されます。
設定ファイルに書かれた内容でテンプレートから参照出来るので、ここに書いておいきレイアウトファイル等では {{ site.author.name }} のように参照すると良いと思います。
permalink: /blog_archive/:year/:month/:day/:title ← ブログのURL(ディレクトリー)構造 exclude: [".rvmrc", "Gemfile", "Rakefile", ".gitignore"] ← 公開しないファイル sitename: EY-Office ← レイアウト、RSS等で使う設定値 production_url : http://www.ey-office.com title : EY-Office author : name : Yuumi Yoshida email : yy@ey-office.coms auto: true ← 自動更新 pygments: false ← コードハイライト server: true ← 確認用サーバー起動 server_port: 4000 ← 確認用サーバーのポート番号
原稿ファイル index.textile
原稿は TextileやMarkdown のようなマークアップ言語で書きますが、htmlを書く事も出来ます。マークアップ言語の区別は拡張子で行っているようで Textileは .textile、Markdownは .md です。
先頭の --- に挟まれた部分はレイアウトの選択やカテゴリーなどを指定します。この情報もレイアウトファイル等から参照できます。( 詳細は https://github.com/mojombo/jekyll/wiki/yaml-front-matter )
また、レイアウトのところで説明する、 Liquidテンプレート言語も使えます。
--- layout: home --- h1. お知らせ * ブログを更新しました "(detail_link){{ site.posts.first.title }}":{{ site.posts.first.url }} * Facbookページを始めました "http://www.facebook.com/ey.office.jp":http://www.facebook.com/ey.office.jp です。 h2. 企業向けソフト開発のプライベートレッスン EY-Officeの教育は画一的な集合教育ではなく、御社の開発プランや開発者のスキルに合わせた教育を御社に出向き実施します。 "(detail_link)詳細はこちら":/education.html !/images/edu_flow.jpg(EY-Officeの教育)! ...
ブログ原稿ファイル 2012-06-11-is-mac-expensive.html.textile
ブログ原稿はブログ独自の処理が加わるので _post ディレクトリーに置きます。
ブログの原稿はファイル名に日付やURLになるファイル名を付けます (詳細は https://github.com/mojombo/jekyll/wiki/permalinks )
また先頭部分の title: にタイトルを書きます。
--- layout: blog title: Macは本当に高いのか? --- iPhone(iOS)アプリの開発にはMacが必要になります、Ruby on Railsの開発にもMacは最適です。しかし世の中ではMacは高いというイメージがあり導入をためらっている方もいるかと思います。今回は本当にMacはWindowsPCより高いの検証してみたいと思います。 h3. 同じスペックのマシンで比較してみよう 本日(2012年6月10日)の時点で Apple Storeを見てみると MacbookAirの一番安い機種は¥84,000です。DELLのホームページを見ると一番安いノートPCは ¥44,980 です。 Macは高い・・・? ….
レイアウト default.html
レイアウトは html で書きます。 {{ … }} や {% … %} の部分は Liquid というテンプレート言語で、値の埋め込み、ファイルインクルード、判断、繰り返しなが出来ます。(Liquidの詳細は https://github.com/shopify/liquid/wiki/liquid-for-designers 、参照出来る値は https://github.com/mojombo/jekyll/wiki/template-data )
{{ content }} の部分に原稿がhtmlに変換された内容が入ります。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> {% include header.html %} <body> <div class="all_area"> <div class="header"> {% include menu_bar.html %} </div> <div class="main_area"> <div class="side"> <img src="/images/ey_logo3.jpg" alt="EY-Office"> {% if page.left_link != '' %} <div class="links"> {{ page.left_link }} </div> {% endif %} </div> <div class="contents"> {{ content }} </div> </div> {% include footer.html %} </div> {% include google_analytics.html %} </body> </html>
共通ファイル header.html
複数のレイアウト等の共通部分をここに置き、インクルードして使います。このファイルでも Liquidテンプレート言語が使えます。
<head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta name="description" content="EY-Officeの教育は画一的な集合教育ではなく、御社の開発プランや開発者のスキルに合わせた教育を御社に出向き実施します。"> <meta name="keyword" content="iPhone,アプリ内課金, In App Purchase, ソフトウェア,教育,講習,トレーニング,OJT,Ruby,Ruby on Rails,Rails,Lisp,scheme,アジャイル"> <meta http-equiv="Content-Style-Type" content="text/css"> <meta http-equiv="Content-Script-Type" content="text/javascript"> {% if page.layout == 'blog' %} <meta property="og:title" content="{{ page.title }}" /> <meta property="og:type" content="blog" /> <meta property="og:url" content="{{ site.production_url }}{{ page.url }}" /> <meta property="og:site_name" content="EY-Office homepage" /> <meta property="fb:app_id" content="133002700083354" /> {% endif %} <title>企業向けiPhone、Ruby on Rails開発のプライベートレッスンならEY-Office</title> <link href="/css/base.css" rel="stylesheet" type="text/css"> <link href="/rss" rel="alternate" title="EY-Office RSSフィード" type="application/rss+xml"> <link href="http://feeds.feedburner.com/ey-office" rel="alternate" title="EY-Office ブログ" type="application/atom+xml" /> </head>
Liquid 応用編
下はブログの一覧表示ページの原稿です。 site.posts に全てのブログエントリーが入っていますので、 Liquidテンプレート言語を使い、そこから最新10件を取り出して、タイトル、リンクと記事の先頭160文字を付けた一覧を生成します。
--- layout: default --- h1. EY-Office ブログ <div class="essay"> div(header). EY-Office取締役 吉田裕美が、まだ Ruby on RailsやiPhone開発を行ってない技術者や技術系マネージャー向けに、技術や教育に付いて書いています。 h1. ブログ一覧 {% for post in site.posts limit:10 %} <div class="blog_list"> <h4><span class="date">{{ post.date | date: "%Y-%m-%d" }}</span> <a href="{{ post.url }}">{{ post.title }}</a></h4> <div>{{ post.content | strip_html | strip_newlines | truncate: 160 }} </div> </div> {% endfor %} </div>
プラグイン menu_image.rb
Liquidテンプレート言語である程度の処理は書けますが、出来ないこともたくさんあります、そんな時はプラグインを作ります。詳細は https://github.com/mojombo/jekyll/wiki/Plugins に書かれていますが、プラグインには
- Generators: 原稿からhtmlに変換するさいにページの自動生成などを行う
- Converters: Markdown,Textile に代わるようなマークアップ言語を組み込む
- Tags: Liquidテンプレート言語に独自のタグを追加する
- Liquid filters: Liquidテンプレート言語に独自のフィルター(関数)を追加する
などが容易されています。プラグインのコードは _plugins ディレクトリーに置くだけで動きます (確認用サーバーは再起動の必要があります)
EY-Officeのホームページでは 以下の画像のように選択されてるタブのマーク画像が変わりますが、その切り替えを行う Tags を書きました。
module Jekyll class MenuImageTag < Liquid::Tag Syntax = /(.*)\s*,\s*(.*)\s*/o def initialize(tag_name, markup, tokens) if markup =~ Syntax @regexp = Regexp.new($1) @url = Liquid::Variable.new($2) else raise SyntaxError.new("Syntax Error in 'menu_image' - Valid syntax: menu_image [regexp], [url]") end super end def render(context) if @regexp =~ @url.render(context) '<img src="/images/menu_sel.gif" alt="*">' else '<img src="/images/menu_unsel.gif" alt="*">' end end end end Liquid::Template.register_tag('menu_image', Jekyll::MenuImageTag)
- 呼び出し側
<table class="menubar"> <tr> <td> {% menu_image ^/index.html, page.url %} <a href="/">Home</a> </td> <td> {% menu_image ^/news, page.url %} <a href="/news/">ニュース</a> </td> <td> {% menu_image ^/company, page.url %} <a href="/company.html">会社案内</a> </td> <td> ....
独自タグの作り方の詳細のドキュメントはありませんので、Liquid テンプレート コード https://github.com/Shopify/liquid を読んで学んで下さい ^^)
6/21日 Jekill を使う人に見つかるように、タイトルを換えました。
今日の結論: Jekyll は便利。ドキュメントが無くてもコードを読めばわかる
MacでRuby on Railsを始めるには RailsInstaller !! Ruby,Rails,Git... が1クリックでインストール完了
Mac OS X には最初から RubyやRuby on Railsが入っていますがバージョンが古く現実的ではありません。最新の Ruby on Railsを使うには、 Xcode入れて、 rvm 入れて、 Ruby 入れて、Railsを入れて、MySQLとかをインストールするために Homebrew いれて 。。。 とかなりたへんです でした。 しかし RailsInstaller が出来たのでワンクリックでインストールが完了します。
VMWareFusion 4
私のMacには既に Xcode,rvm,Ruby,Rails,Homebrew, ... が入っているし、この環境を消してまでRailsInstallerのテストは行えません。そんな時には VMWareFusion 4 です。VMWareFusion 4ではWindowsやLinux以外に Mac OS X Lion を動かす事ができるのです! インストール実験にはもってこいの環境です。
下の画像は VMWareFusion 4 の上で Mac OS X Lion を動かしている Mac OS X Lionの画面です。Macの中にMacがあるのがわかりますか?
インストール
http://railsinstaller.org/ をアクセスし RailsInstaller をダウンロードし、インストールします。通常のMacアプリと同じです。とくに説明はいりませんが http://railsinstaller.org/ にあるビデオを見ると手順がわかります。
インストール前は ruby 1.8.7 がインストールされています、git や gcc は入っていません。
chappy-vm:~ yy$ ruby --version ruby 1.8.7 (2011-12-28 patchlevel 357) [universal-darwin11.0] chappy-vm:~ yy$ git --version -bash: git: command not found chappy-vm:~ yy$ gcc --version -bash: gcc: command not found
インストール後に、再度ターミナル(Shell)を起動すると、Ruby 1.9.3, Rails などがインストールされています。
chappy-vm:~ yy$ ruby --version ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-darwin11.3.0] chappy-vm:~ yy$ git --version git version 1.7.4.4 chappy-vm:~ yy$ gcc --version i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00) ... chappy-vm:RailsWorks yy$ rails --version Rails 3.2.2
早速 Todo アプリを作ってみましょう
chappy-vm:RailsWorks yy$ rails new todo_app create create README.rdoc create Rakefile .... run bundle install Fetching gem metadata from https://rubygems.org/......... Installing rake (0.9.2.2) Using i18n (0.6.0) Installing multi_json (1.3.6) ... chappy-vm:RailsWorks yy$ cd todo_app/ chappy-vm:todo_app yy$ rails g scaffold todo due:date task:string invoke active_record create db/migrate/20120603031721_create_todos.rb ... chappy-vm:todo_app yy$ rake db:migrate == CreateTodos: migrating ========================================== -- create_table(:todos) -> 0.0011s == CreateTodos: migrated (0.0017s) ================================= chappy-vm:todo_app yy$ rails s => Booting WEBrick => Rails 3.2.2 application starting in development on http://0.0.0.0:3000 ...
ちなみに RailsInstaller は rvm を使っているので、慣れてくれば 複数のバージョンの Ruby、複数のバージョンの Railsを1つの Mac にインストールして使う事ができます。
Jewelrybox
今回、初めて知ったのですが RailsInstaller には Jewelrybox というアプリが含まれています。
これは、 rvm をGUIベース管理できるツールです。GUIが好きな人はインストールしてみると良いと思います。
今日のまとめ: Mac買ったらすぐにいれるべきソフト RailsInstaller
Active Merchant で PayPal Sandbox を使うには
Ruby on Railsで作ったWebサービスからPayPalや海外の決済サービスを使う場合、そのサービス固有のAPIを使わなくても Active Merchant を使うと、簡単に信頼性の高い決済を組み込めます。
Active Merchant の使い方は 以下の3つのRailsCastを見るのが一番良いと思います。
- #144 Active Merchant Basics - RailsCasts
- #145 Integrating Active Merchant - RailsCasts
- #146 PayPal Express Checkout - RailsCasts
RailsCastを見て、サンプルコードを動かすのは簡単です、またサンプルは Rails2.2.X用ですが Rails 3.0.X でも少しの修正で動かせました。
ところが、テスト用に PayPal を使おうとしたのですが、これがわかりにくい !!
たんに英語力が低いだけかもしれませんが、苦労した結果をまとめておきました。
PayPal sandbox にテスト用にアカウント作成方法
まず、PayPalの決済には利用者側でクレジットカード番号等を入力し決済を呼び出す PayPal Payments Standard と カード番号等は PayPalのページで入力する Express Checkout の2つがりあすが、今回は PayPal Payments Standard の話です。
1. PayPal sandbox に登録する
PayPal sandbox を使うための登録を行います、ここで登録する e-mail アドレスは受信出来るアドレスで、かつPayPalを使うために登録してあるアドレスとは別のアドレスで登録して下さい。
PayPal Sandbox - Log In
2. 決済のテストで使うアカウントを作成する
決済をテストするためには2種類のアカウントが必要です
- お金を受け取る(ネットショップ など)側の Bussiness アカウント
- お金を払う(お客様など)側の Personal アカウント
Test Accountページの New test account: Preconfigured をクリックしてアカウントを作って下さい。Create Manually を使うと日本語名のアカウントが作れますが、私が試した範囲では上手く決済できませんでした。
Preconfiguredをクリックすると下のような画面が表示されます、ここで重要な事は
- Country: を United States にする
- Account Typeは
- ネットショップ 側は Seller
- お客様側は Buyer
- First name, Last name はお客様側では入力しておくと良いと思います
- メールアドレスは適当なアドレスが設定されています。実際にメールを受信する必要はないのでデフォルトで良いと思います。
- Passwordは適当な値が入っていますが、自分の覚えやすいものに替えた方が良いとおもいます
後はそのままで Create Account して下さい。
下の画像のように、Bussiness, Personal 2つのアカウントを作成します。View Details で表示される情報の中に テストで使える クレジットカード番号があるので Personalアカウントのカード番号をメモしておくと良いと思います。
また、左側の Test Emailメニューでこのアカウントのメールアドレスに送られてきたメールを読めます。
Rails2.3アプリをRails3.2にアップグレードする、その3
少し間が開きましたが、今回はメール、Cucumber、Javascriptまわりです
メール送信
ActionMailer
メールは Rails3で ActionMailerで仕様が以下のように少し変わりました。またActionMailerを継承したクラスは app/mailers に置くようになりました。
仕様の変更は機械的に変更できるものばかりですね。
- Rails 2.3
class CustomerMail < ActionMailer::Base helper :application # パスワード再設定用メールの送信 def password_reset(to_addr, url, timeout, name) subject "パスワードの再設定" recipients to_addr from FROM_ADDRESS body :url=>url, :timeout=>timeout, :name=>name end ・・・
- Rails 3.0 以降
class CustomerMail < ActionMailer::Base helper :Application # パスワード再設定用メールの送信 def password_reset(to_addr, url, timeout, name) @url = url @timeout = timeout @name = name mail( :subject => "パスワードの再設定", :to => to_addr, :from => FROM_ADDRESS) end ・・・
テンプレート (view)
メールのテンプレート (view)はほぼそのまま使えます。ただし < & > 等がエスケープされますので、raw を追加する必要がある部分もあるかもしれません。
日本語
あいかわらず、日本語メールが送れません ^^);
mail-iso-2022-jp という gem をインストールすると ISO-2022-JP のメールが送信できます。 ただし、この場合は UTF-8からJISコードに変換出来ない文字でエラーが発生するので、何らかの対応を考えておく必要があります。
最近はPCはもちろん、携帯でもUTF-8のメールを受信出来るようなので、UTF-8で送信すれば上の文字コードの問題は発生しません(一部のメーラー、携帯では文字化けするかも知れませんが・・・)。
私が Rails3.0以降に作ったシステムでは UTF-8で送信していますが、今のところ問題は無いようなので、今回もUTF-8で送信する事にしました。
Rails3で送信するメールの本文をbase64ではなく8bitにする方法 - 思っているよりもずっとずっと人生は短い。 を参考に、 Mail::Message deliver_jp メソッドを追加して使っています(もちろん deliverを置き換えても良いのですが・・・)。
module Mail class Message def deliver_jp self.tap {|m| m.transport_encoding = '8bit'}.deliver end end end
Cucumber
このアプリでは受け入れ(統合?)テストを Cucumber で書きました。 その時点ではCucumber 0.8.3 で Webrat を使っていました。 今回は Cucumber 1.1.9 + Capybara-webkit です。
設定や基本的なstep ファイル
設定や web_steps.rb 、 web_steps_ja.rb は空のRailsプロジェクトにCucumberをインストールして出来た物をベースに必要な部分のみ Rails2.3からコピーしました。
step の中で 他のステップを利用する場合は step と書くように変わったんですね
- Cucumber 0.8.3
When /^"([^\"]*)"ボタンをクリックする$/ do |button| When %Q(I press "#{button}") end
- Cucumber 1.1.9
もし /^"([^"]*)"ボタンをクリックする$/ do |button| step %{I press "#{button}"} end
シナリオ(フィーチャー)
Cucumberが正常に動くようにるにのに手間がかかりましたが、ほとんどのシナリオはそのまま通りました。
問題があったのは
- 画像をボタンのように使っている場合
<a href="action"><img src="a_button.png" title="Aボタン"/></a>
上のHTMLは もし "Aボタン"リンクをクリックする と書けたのですが、Captbaraは画像のtitleを見てくれません。ここは仕方なく もし "a_button"リンクをクリックする と変更しました。(a タグにtitleを付けたりしたのですがダメでした・・・・)
- エラーメッセージ
Rails2.3ではvalidationのエラーメッセージは 名前 を入力して下さい のように入力項目とエラーメッセージの間にスペースがあったのですがRails3.2では無くなっていましたので修正しました。
- visit のオプション引数
Webrat では visitのオプション引数でパラメターやメソッド(POST,PUT...)を指定できたので Javascript でリンクからPUTを送る部分は、これを使ってテストしていましたがCapybaraではvisitのオプション引数はありませんでした。
しかし、今回はJavascriptが動作するCapybara-webkit なので step はリンクのクリックを書くだけで正しくテストが行えました。素晴らしい!
Javascript関連
- :method => :delete のリンク
: method => :delete のリンクが正しく動作しませんでした。 じつはRails2.3の時点で jquery を使っていたので jquery.js ファイルもそのまま使っていましたが、バージョンが1.3.2 と古く、これが原因でした! Rails3.2の jquery.js を使うようにしたら動きました。
- :method => :delete のリンクをクリックすると Can't verify CSRF token authenticity が発生
ログアウトリンクをクリックすると、セッションが消えてしまう(新しくなってしまう)という不思議な現象が発生していました。ログを良くみると WARNING: Can't verify CSRF token authenticity と出ていいます。たしかに authenticity_tokenが来ていません・・・・・ ここで、Rails3のlayoutテンプレートの
の最後に <%= csrf_meta_tags %> が在ることを以前から不思議に感じていた事を思い出し、layoutテンプレートに加えたところ、正しく動作するようになりました ^^)/Rails2.3からRails3.2へのポーティングはかなり完成に近づいて来ました。
バラバラのバージョンのRuby on Railsを1つのサーバーで動かす
現在、EY-Officeの社内利用サーバーではではいろいろなバージョンのRuby on Rails を2台で管理しています。ただし全てがほぼ私ししか使っていないので、さくらVPSのキャンペーン につられて1つのサーバーにまとめてみました。
移行前
さくら VPS 512Mをつかって以下のアプリを運用していました (1.8.7@rails2.3 という記法は rvmで使う記法で Ruby 1.8.7 で Rails 2.3.X を使っているという事です)
- サーバー1
- redmine : 1.8.7@独自、教育で使ったりするので時々負荷が高くなる
- radiant : 1.8.7@独自、EY-Officeホームページ作成用、スタティックページを生成して使うので超低負荷
- Ruby on Rails以外: gitリポジトリー、wliki ( Gaucheで書かれたWiki )
- サーバー2
- A社ステージング : 1.8.7@rails2.3 、低負荷
- B社ステージング : 1.8.7@rails2.3、 お客様側の開発者もたまに使うが、低負荷
- C社テスト用 : 1.8.7@rails3.0、 低負荷
さらに、A社サービスを 1.9.3@rails3.2 に移行中でステージングサーバーを必要としています。
方針
今までは、Ruby on Railsの実行環境は Apache + Passenger を使っていました。PassengerはApacheのモジュールとして動くのでアプリの設定やデプロイが簡単ですし、1つのサーバーで複数のアプリを動かすのも簡単です。
開発環境(Macbook Pro)はrvm を使って複数のバージョンの Ruby/Railsの開発が出来ます、rvm をサーバー上で使えば同じように複数のバージョンの Ruby/Railsの運用が出来るのでは? と考え調べてみました。
Passenger を rvm の上で動かす事は rvmのページ に書かれているように簡単にできます。 しかし、Passenger で動くアプリで複数のRubyを使う事は出来ません! Passengerのblogに 複数のバージョンのRubyをPassengerで動かす方法というエントリーがありますが、図のように 異なるRubyを使うアプリは Passengerをスタンドアロンで起動して使うと書かれています・・・・・ これでは、手軽に使える Passengerの良さが失われてしまいます ^^);
Apacheを reverse proxyにしてアプリケーションサーバーを別に起動するなら、Passenger以外に Unicornという選択肢もあります。いろいろと調べた結果
rvm wrapper 1.8.7@2.3 rails2.3 unicorn_rails
- 起動スクリプト(/etc/init.d/xxxx)はrootで動作しますが、unicorn の実行は su - でrvmのインストールされたユーザーで実行すればよい
- unicornはPassengerと同等の性能でメモリー使用量が少ない(らしい)
ということで、rvm + unicorn でRails を運用すれば、好きなバージョンの Ruby 、 好きなバージョンの Rails を 複数起動できます。
現状
ただし、お客様の環境もPassengerで動いていますのでステージングはPassengerで動かしておいた方が良いと思います。そこで今回の移設では
- 新サーバー
としました。 新サーバーは 2Gメモリーなので、これだけ動かしても快適です :-)
Rails2.3アプリをRails3.2にアップグレードする、その2
RSpec
今回のプロジェクトでは、 全model、全lib (少しですが)、view のごく一部にたいしての RSpecが書かれています。
Rspecのバージョンは 1.3.2 から 2.8.0 へのアップグレードでした。
model
- バリデーションのテストで、その入力フィールドでエラーが出ているのかを
c.errors.on(:name).should_not be_nil
↓ のように変更
c.should have(1).errors_on(:name)
- libと同じく UTC の問題、日時をチェックしてる部分は多数あるので変更量は多かったですが、エディターがやってくれました。
view
view/controller周りは RSpec 2.0 で仕様変更があり、RSpecコードの変更が必要です。
- テスト対処のviewが partialの場合は
describe "_order_list.html.erb" do ... render "order/_order_list"
↓ のように変更
describe "order/_order_list.html.erb" do ... render
- assigns がなくなった?
assigns[:order] = orders(:or01)
↓ のように変更
assign(:order, orders(:or01))
- response.should have_tag が動かなくなった
response.should have_tag('#unit_price2', /¥30,000/)
↓ のように変更
rendered.should have_tag('#unit_price2', /¥30,000/)
性能測定
だいたい動くようになったので、開発サーバーにデプロイし 2.3版と 3.2.2版の性能を測ってみました。環境をそろえるために、両方とも Passenger 3.0.11 で動かしました。
サーバーは さくら VPS 512 でメモリーは512Mbyte です。
メモリー使用量
ab コマンドでページをアクセスし、top でrubyプロセスを測定しました。
環境 | VIRT | |
---|---|---|
Ruby1.8.7 + Rails2.3.10 | 140m | |
Ruby1.9.3 + Rails3.2.2 | 185m |
Rails2.3アプリをRails3.2にアップグレードする、その1
以前Ruby on Rails 2.3 (Ruby1.8.7) で作ったアプリを、Rails3.2 (Ruby 1.9.3)にアップグレードしようと決意しました。
ただし、それほど性能の良いサーバーで稼働しているわけではないので、3.2にした時の性能(リソースの使用量)等も気になりますので早めに動かし性能を測定する事にしました。
1. とりあえずRails3.2で動かす
Rails3.2環境に移行
現行のRails2.3のコードを使うのですが、app/assetsやconfig以下などは Rails3.2に合わせないと行きません。そこで Rails3.2.3のRailsコマンドの空のプロジェクトを作成し、そこから(元のconfigはリネームし) config やapp/assets などを持ってきて Rails3.2の環境に合わせる
準備
- 必要なライブラリー、プラグインを Gemfileに登録。 fastercsv や will_paginate など止めたい物もありますが、まずは動かす為にぐっとこられました ^^;
- Ruby1.9用にマジックコメントの追加、magic_encoding で一発
エラー、問題点をひたすらつぶす
問題になった点を上げておきます
- RAILS_ENV → Rails.env 、 RAILS_ROOT → Rails.root
- lib/ が読み込まれないので config/application.rb に config.autoload_paths += %W(#{Rails.root}/lib) を追加
- named_scope → scope
- filter_parameter_logging を消す
- <% form_tag → <%= form_tag
- app/assetsの作成
- public/{images,javascripts,stylesheets} を app/assets へ移動
- application.js , application.css の作成
- def before_save のようなCallbackメソッドが廃止されたので before_save :before_save_.... に置き換え
- 文字コードの正規表現の一部変更 (Ruby 1.9)
- htmlタグを戻すhelperメソッドに raw() を追加
- XSSセキュリティーホールを作らないように、必要な部分には html_escape()
- [1,2,3].to_s → [1,2,3].join (Ruby 1.9)
- Module#public_instance_methods の戻りが文字列の配列からシンボルの配列に変わった (Ruby 1.9)
- f.error_messagesメソッドが無くなったことへの対応。以下のようなhelperを作り対応
def form_error_messages!(f) if f.object.errors.any? errs = f.object.errors.full_messages.inject("") do |result, msg| result + " <li>" + msg + "</li>\n" end raw(%! <div id="error_explanation"> <h2>#{t('activerecord.errors.title')}</h2> <ul> #{errs} </ul> </div> !) else "" end end
感想
いろいろと問題がありましたが、思っていたよりは変更作業は少なかった気がします。皆さんも Rails2.3 アプリの Rails3.2対応にトライして下さい ! もちろんテスト(RSpec...) ありますよね :-)