ホーム > タグ > Rails

Rails

RSpec2+Rails3+autotest環境の構築

9月からやる仕事がめでたく、Rails3.0 + Ruby1.9.2のお仕事なので色々と環境構築。とりあえず自動テストまわりやりました。

一応、環境を他と切り分けるために、rvmでアプリ用にgemsetを用意。アプリごとに簡単に環境を構築できるrvmマジ便利。

gem install bundler --pre
gem install rails

まずは、bundlerとrailsをインストール。次は適当なアプリを作って必要なgemのインストールなどを行う。テストはRSpecで書くので、-TをつけてTest/Unitは使わないようにする。

rails new demo -T

次に必要なgemをGemfileに記述。rspecとかを「テストだけだから」と思って、gropu :testにしたら、モデルを作成したときにTest/Unitのテストコードが作られたりしたので注意。githubのWikiを見るとautotestのgemは不要そうなんだけど、実際ないとうまくautotestが動かなかた。

bundle install

あとはモデルを作って、テストが実行できればOK。

rails g model user
rake
autotest

追記

Twitterで@conceal_rsさんから補足ありました。ありがとうございます!

@ukstudio ZenTestとautotest-railsはなくても大丈夫ですよ。あとrspecは2.0.0.beta.20からwebratに依存しなくなったのでhave_selectorとか使えなくなってます。gem ‘webrat’もあった方がいいかもless than a minute ago via Termtter

warden+railsでパスワード認証

今作っているサービスが後々、OAuth、OpenIDあたりにも対応することになるかもしれないので、そのあたり柔軟に対応できそうなwardenを試してみました。

必要なgemはwardenrails_wardenの2つ。

Userモデルは以下のような感じで。

次にgithubのページを参考にconfig/initializers/warden.rbを追加します。今回はパスワードで認証をしたいのでpasswordのstrategyを自分で追加します。(と言ってもほとんどサンプルと同じ)

この後はUser.authenticateの中身をfind_by_login_and_passwordとかで実装してもいいのですが、それだとパスワードが平文になってしまうのでrestful_authenticationのコードを少し拝借することにします。


includeいているものがrestful_authenticationのコードです。適当にコピーしてlibにでも置いておくといいと思います。

これでpasswordとpassword_confirmationによるパスワードの確認、User#save時にパスワードをハッシュ化して保存してくれます。

後、一応ログイン処理するコントローラも載せておきます。

unauthenticatedが認証に失敗したときに遷移するアクションです。

正直、パスワード認証のことだけ考えるとちょっと面倒な気もします。パスワードの暗号化も自分で書かなければいけないし。ただ、上記のようにmoduleを別途用意しておけば作業の手間自体は結構軽減されので、そこまでは問題にならないかもしれません。

Strategyまわりについてはほとんど検証していませんが、色々と融通は効きそうな気もします。この辺は追々。

後はdeviseというwardenベースのライブラリもあるのでこれを試すのもありかなという気はします。ただ、deviseは色々とやり過ぎというか、多機能すぎてよくわからない感じもしますが・・・

CentOS 5.4(EC2)にApache+PassengerでRails環境作る

後々、また参照する気がするので記録しておく。この手の環境構築系のドキュメントってWikiかなんかにみんなで情報集めたらそこそこ便利そうな気がするのだけどどうだろう。

Ruby、RubyGemsのインストール

yumでRubyをインストールしようとすると、1.8.5が入ってしまうので仕方なくソースからインストール。

$ cd /usr/local/src
$ sudo wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p249.tar.gz
$ sudo tar zxvf ruby-1.8.7-p249.tar.gz
$ cd ruby-1.8.7-p249
$ sudo ./configure
$ sudo make
$ sudo make install

$ cd /usr/local/src
$ sudo wget http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz
$ sudo tar zxvf rubygems-1.3.6
$ cd rubygems-1.3.6
$ sudo ruby setup.rb

この時点で一応RubyGemsもインストール出来てはいるけれど、実際に使おうとするとエラーが発生する。どうやらzlibが入っていなかった模様。

$ sudo yum install zlib-devel
$ cd /usr/local/src/ruby-1.8.7-p249/ext/zlib
$ sudo extconf.rb --with-zlib-include=/usr/include --with-zlib-lib=/usr/lib
$ sudo make
$ sudo make install

MySQLのインストール

こっちはyumからサクッとインストール。

$ sudo yum install mysql mysql-server mysql-devel
$ sudo /etc/initd.mysqld start

my.cnfの設定は/usr/share/mysql/以下からコピーしてきたりとか適当に。ユーザの設定とかも適当に。

Apache+Passenger

まずはApacheをサクッとインストール。

$ sudo yum install httpd-devel

そしてPassengerのインストール。

$ sudo gem install passenger
$ sudo passenger-install-apache2-module

ここでまたしてもエラー。どうやらOpenSSLが入っていないとかなんとか。

$ sudo yum install openssl-devel
$ cd /usr/local/src/ruby-1.8.7-p249/ext/openssl
$ sudo ruby extconf.rb
$ sudo make
$ sudo make install

これで無事Passengerがインストール出来る。

$ sudo passenger-install-apache2-module

最低限のPassengerの設定。この設定の内容はpassenger-install-apache2-moduleを実行した時に表示されているので確認しておくこと。

$ sudo vi /etc/httpd/conf.d/passenger.conf
LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.11/ext/apache2/mod_passenger.so
PassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.11
PassengerRuby /usr/local/bin/ruby

あとはhttpd.confのDocumentRootをRailsのpublicディレクトリにすればOK。

$ sudo vi /etc/httpd/conf/httpd.conf
DocumentRoot /path/to/rails/public

本当に最低限だけどとりあえずこれでPassengerでRailsを動かすことが出来るはず。ApacheやMySQLの自動起動はchkconfigを設定すればよい。Passengerの細かい設定はPassenger users guidを参考に。

RailsからOAuthを利用してTwitterにポストする

OAuthの細かい説明は抜き。

まず、OAuthを使うためにはTwitterでアプリケーションの登録が必要なので、http://twitter.com/oauth_clientsで登録をしておいてください。 以下のコードの6行目の部分を取得したConsumer keyとConsumer secretをに置き換えてください。

適当なところからverifyアクションにリダイレクトしてくると、さらにTwitterにリダイレクトします。その後、callbackアクションに戻ってくるので、そこで認証して取得したトークンをUserモデルに保存します。(ここでは自分のサービスにログインしているユーザが認証を行っています。)

その後、保存したトークンを使ってTwitterに発言をします。リクエストが受け入れられなかった場合の処理などは省いてます。

Twitterには取得したトークンに有効期限はありませんが、有効期限が存在するものもある(どちらかというとそっちの方が多いのかも)気をつける必要があります。

ちなみに細かいことを調べていないので「トークンをDBに保存してしまっていいのか」とか「トークンが外部に漏れてしまった場合はどうしたらいいのか」などについてはよくわかっていません。

WEB+DB PRESS Vol.51でRailsの特集を執筆しました

WEB+DB PRESS Vol.51
WEB+DB PRESS Vol.51 WEB+DB PRESS編集部

技術評論社 2009-06-24
売り上げランキング : 130

Amazonで詳しく見る by G-Tools

僕個人っていうわけではないですが、会社の人達と一緒に6月24日発売のWEB+DB PRESS Vol.51で執筆させて頂きました。初めての執筆活動なので、読みにくい部分、至らない部分などあると思いますが、買って読んで頂けると幸いです。

Cucumber+email_specでActionMailerのテストをする

今までメール(ActionMailer)のテストはどうにも面倒で、自分でブラウザから動かしてログを見てってやっていたんですが、Cucumberでメールのテストもできるっぽいので試してみました。

確認環境はRails2.3.2、Cucumber0.2.3、email_spec0.0.10。

email_specはgithubをsourceに指定してインストールすることができます(bmabey’s email-spec at master – GitHub)。config/environments/test.rbあたりに書いておくといいと思います。

email_specをインストールするとgenerateにコマンドが追加されています。

$ ruby script/generate email_spec

ここで生成されるfeatures/step_definitions/email_steps.rbは英語なので日本語に直したものを使います。

これは僕がこないだ出向していたときのプロジェクトに使われていたものなので、多分その出向先の誰かが作ってくれたものだと思います。ありがとうございます。

最後にemail_specを使えるようにfeatures/support/env.rbに

require 'email_spec/cucumber'

を追記してやります。あとはシナリオにテストケースを書いてテストすればOKです。

 ならば "example@hoge.com" がメールを1通受信していること

ちなみにメールの文章中にあるURLに遷移することもできるので、例えば仮登録→メールで認証URL→本登録という流れもちゃんとテストできます。

Cucumberの登場でRailsのテスティング環境が変わった

ちょっと大げさなタイトルかもしれないですが、個人的にはそれぐらいの感動。「これで勝つる!」な気分。何に勝つのか知らないけれど。

今までのRailsのテストはもっぱらRSpecで書いてて、確かにこれはこれで素晴らしい。採用当初はバグが減ってその時も「これで勝つる!」な気分でした。でもやっぱり受け入れテストがネックになるんですよね。Seleniumとかも使ったりしてましたけど、ブラウザががちゃがちゃ動くし、なんとなく面倒で結局手動で確認という感じになってしまいました。

そこでCucumberの登場ですよ。個人的に素晴しいと思うのは

  • テストケースが自然文(っぽい)
  • そんなに邪魔じゃない

あたりかなぁ。テストケースが自然文っぽいというのは実はかなり大事で例えば

お客さん: まずトップページにアクセスするとログインフォームがあって、そこにログインすると「ようこそ!ほげほげさん」と出すようにして欲しい

っていう要望、つまりユーザーストーリがあった場合に割とそのままシナリオとしてテストに変換できる。

もし トップページ にアクセス
かつ メールアドレス に hogehoge@hoge.com と入力
かつ パスワード に hogehoge と入力
かつ ログイン ボタンを押す

ならば ようこそ!ほげほげさん と表示されること

これは疑似言語とかじゃなくて、これがそのままテストとして実行できる。つまり今までこっちがブラウザをポチポチしてお客さんに「できましたー(多分)」と報告していて、お客さんからすると何をどうテストしていたのかが曖昧という問題があったのだけれど、 Cucumberだとお客さんと一緒に受け入れテストを作ることができて、そのテストケースもお客さんが読むことができるから曖昧さが消えて安心が生まれる。

もちろん開発者にもメリットはあって、Cucumberはユーザ視点レベルのテストだからテストとしては一番外側なテストでここのテストがちゃんと通っていれば、アプリケーションの動作がユーザ視点での正しく動くという保証ができるわけです。

その保証ができるとどうなるかと言うと、極端な話、ユーザ視点での動作が正しければ内部の動作なんて割とどうでもいいわけで、内部に自由がでてきます。内部に自由がでてくると、コードの修正や設計の変更が怖くなくなり、リファクタリングがしやすくなります。結果、メンテのしやすいアプリが出来上がります。

Cucumberは残念なことに、Ajaxのテストができないのでその辺りはSeleniumや手動での確認、あとはjsonやxmlを吐き出すアクションをRspecでテストするなど臨機応変に対応する必要がありそうです。

最後にオマケですが、僕が実際にCucumberを使ったときの開発の流れをば。

  • Cucumberのシナリオを書く
  • Rspecでモデルのテストを書く
  • モデルにロジックを書く
  • Rspecでコントローラとビューのテストを書く
  • コントーラとビューを書く
  • Cucumberのテストが通ったのを確認して、実際に手動でも確認する
  • それぞれのテストをautotestとかでまわしながらリファクタリング

まず最初にCucumberのシナリオを書きます。仕様のブレを防ぐためです。この時点では当然Cucumberのテストは通りませんが、とりあえずモデルからビューにかけてボトムアップでコードを書きます。基本的にテストファーストです。

ビューまで書いたらこの時点でCucumberのテストが通っていれば手動で確認、通っていなければ同じ要領でテストファーストでコードを書きます。

最後に今まで書いたテストが落ちないようにリファクタリングを行います。ここまでで1つのユーザストーリ(Cucumberでいうフィーチャ)の実装が完了します。

CucumberはRspecの時もそうでしたが、新しく導入するときにどうしてもコストがかかります。でも慣れてくればそのコストは大分減りますし、stepもある程度使いまわせるものが多いので長期的に見れば逆にコストが減ると思っています。個人的にはCucumberを採用しない理由はないと思うので、この記事を読んでいる人も是非試してみてください。

  • Comments (Close): 0
  • Trackbacks (Close): 0

accepts_nested_attributes_forしたモデルの日本語化

名前、長いよね。accepts_nested_attributes_for。以下、ネストしたって言います。長いので。

最近はもっぱら日本語化はi18nにしてるんですが、今回ちょこっとこのネスト関係ではまったのでメモ。

とりあえずモデルの作成までガッとやります。Railsのバージョンは2.3.2です。最下行はgemのインストールが必要です(http://github.com/amatsuda/i18n_generators/tree/master)


それぞれアソシエーションとバリデーションのコードを追記しておきます。当然、accepts_nested_attributes_forの記述も必要です。その辺の詳細は省くので適当にググってみてください。

で、日本語化はモデルを作成した後に行なっているのでとりあえずカラムは日本語化されてる筈です。その辺の詳細も省きます。

されてるはずなのですが、一部日本語化されてない箇所があるのでこれを日本語化させます。

userモデルのところにentries_xxxが追記されています。ちなみにhas_oneの場合はentry_xxxになります。xxxはカラム名。

おわり。

Rails2.0.2から2.2.2に上げたらFileColumnがNameErrorだした。

自分の担当している案件のRailsのバージョンを2.0.2から2.2.2に上げたら以下のようなエラーが発生。

uninitialized constant FileColumn::ClassMethods::Inflector (NameError)

これの対応は/vender/plugin/file_column/lib/file_column.rbの以下の部分を

my_options = FileColumn::init_options(options,
                                                 Inflector.underscore(self.name).to_s,
                                                 attr.to_s)

以下のように書き換えればとりあえず対応できる。

my_options = FileColumn::init_options(options,
                                                 self.name.to_s.underscore,
                                                 attr.to_s)

ちゃんちゃん。

Rails2.2のi18n(国際化)を簡単に試してみた

11月21日にRails2.2が正式リリースされた。 RCなどでチェックしてた人は既に知っているかもしれないけど、2.2からデフォルトでi18n(国際化)対応がされている。

ちなみにi18nというのはinternationalizationの頭と後ろのiとn、文字数が18文字というところから来てるらしい。

とりあえず、まずはアプリの作成。

$ rails i18n_demo

作成されたファイル群の中にconfig/locales/en.ymlというファイルが出来ていると思うけど、これが翻訳ファイルになる。今回は英語と日本語を用意しようと思うので、en.ymlをコピーしてja.ymlを作成する。

$ cp config/locales/en.yml config/locales/ja.yml

翻訳ファイルを修正しようにも、そもそもアプリケーションが出来ていないので、scaffoldで簡単に作ってしまおう。

$ ruby script/generate scaffold entry title:string body:text
$ rake db:migrate

とりあえずは適当にサイトタイトル的なものでも作ってみよう。翻訳ファイルに関しては元々あった内容は削除してしまっていい。

# config/locales/ja.yml
ja:
  site_title: サイトタイトル

一応英語も。

# config/locales/en.yml
en:
  site_title: SiteTitle

Viewの修正。

# app/views/entries/index.html.erb

<%= I18n.t :site_title %>

この状態でサーバーを起動し、http://localhost:3000/entriesにアクセスしてみる。「SiteTitle」という文字が表示されているはずだ。この状態だとまだ言語がデフォルトの英語の設定になっている。多分、ブラウザの言語設定とかは見てなさげ?。ちょっとソースを見てないのでまだ未確認。もしかしたら、リクエストのヘッダーを見て言語を決める部分は自分で実装しなきゃいけないのかもしれない。

なんにせよ、日本語で表示したい場合は以下のようにする。

# config/environment.rb
# 最下行に追加
I18n.default_locale = "ja"

これで再度アクセスすれば「サイトタイトル」と表示されているはずだ。

次にGETパラメータで言語が切り替わるようにしてみよう。

# app/controllers/application.rb

before_filter :set_locale
def set_locale
  I18n.locale = params[:locale]
end

これでhttp://localhost:3000/entries?locale=enで「SiteTitle」と表示されているはずだ。

次にモデルの日本語化をしてみよう。まずはエラーメッセージを出すためにバリデーションを追加する。

# app/model/entry.rb
class Entry < ActiveRecord::Base
  validates_presence_of :title, :body
end

http://localhost:3000/entry/newでフォームに何も入力せず送信すればエラーがでるので英語で表示されていることを確認する。

普通のバリデーションのエラーとは違うエラーがでているけど、これは翻訳ファイルをちゃんと書いてないからでているエラー。英語の方はちょっと面倒なので無視するが、とりあえず日本語化をすすめる。

#config/locales/ja.yml
ja:
  site_title: サイトタイトル
    activerecord:
      errors:
        template:
          header: "{{model}}でエラーが発生しました。"
          body:   以下のエラー内容を確認してください。
        messages:
          blank:  が空白です。
      models:
        entry: エントリー
      attributes:
        entry:
          title: タイトル
          body: 本文

以上の修正をして、もう一度エラーを出してみるとエラーが日本語に変わっているはずだ。翻訳ファイルのどの部分がどの部分に対応してるかは雰囲気でわかると思う。

今回は必要な部分だけ翻訳したけど、もうちょっとちゃんとした翻訳ファイルが必要ならRailsをローカライズするも参考にするといいと思う。

諸々めんどくせー!って人は松田さんのRails 2.2の I18nによる日本語化を最も簡単に行う方法へどうぞ。gemで一発です。

まだ2.2はリリースされたばかりで、i18nまわりの日本語の情報はあまり多くはないと思うけど、そこまで複雑な仕組みでもないし、翻訳ファイルに関して言えば基本的な部分(ActiveRecordとか)は使い回しができるので手間もそこまで大きくはないと思う。ブラウザの言語設定での判断もそのうちプラグインがでてくるんじゃないかと思っている。

「国際化とか必要ないよー」の人も、バリデーションのエラーを日本語化するのにgettextを入れる必要がなくなったりとこれでかなりラクになるんじゃなかろうか。

Home > Tags > Rails

Feeds
Meta
Others

Return to page top