インストールするだけですぐに使える本格的な無料Railsプラグイン

よく使うRailsプラグインをリスト。毎回検索してインストールするのが面倒だったので。
ちなみにタイトルはホッテントリメーカーです。無料じゃないプラグインなんて見た事ないけどw160ブクマはいく予感!

rails app_nameしたら即行入れるプラグインたち

Annotate Models

Modelに対応するテーブルのカラム情報をコメントとして付加してくれる。

script/plugin install http://repo.pragprog.com/svn/Public/plugins/annotate_models
Safe ERB

HTMLエスケープを忘れていると警告してくれる。
いつのまにかAgile Web Developmentに乗ってる!と思ったら、さらにGitHubで亜種が出ててびっくり。リンクを張ったものはsqlite3にも対応している模様。

script/plugin install git://github.com/emk/safe_erb.git
Safe Record

SQLエスケープを忘れていると警告してくれる。

script/plugin install git://github.com/authorNari/safe_record.git
Special Warnings

"1" == 1のように文字列と数値を比較しているとログに警告を出してくれる。

script/plugin install git://github.com/authorNari/special_warning.git

なんだかんだで結局どのアプリでも入れてるプラグインたち

jRails

jQuery派なので。Rails標準のprototype.jsをラップしたjavascript helperをjQueryをラップしたものに置き換えてくれる。

script/plugin install http://ennerchi.googlecode.com/svn/trunk/plugins/jrails
Restful Authentication

認証機能一式をごっそり生成してくれる。

script/plugin install git://github.com/technoweenie/restful-authentication.git
Forgot Password

パスワード再設定機能一式をごっそり生成してくれる。

script/plugin install git://github.com/greenisus/forgot_password.git
Active Form

DBに対応したテーブルがなくてもModelを作れる。

script/plugin install git://github.com/zaczheng/activeform.git
Jp Mailer

iso-2022-jpで日本語メールを送りたいときに。

script/plugin install http:/taslam-plugins.googlecode.com/svn/trunk/jp_mailer/

RailsのMigrationをTimestampから連番に戻す

Rails 2系からMigrationファイルのバージョンがTimestampで管理されるようになりましたが、あれエディタで開くとき不便なんですよね。2.2からはconfigで連番に戻せるようになったので、戻しました。

config/environment.rb
config.active_record.timestamped_migrations = false

で、今までTimestampを頭につけて管理されていたものを連番にリネーム。

ruby -rfileutils -e 'Dir["db/migrate/*.rb"].sort.each_with_index {|f, i| FileUtils.mv f, f.gsub(/\d+/, sprintf("%03d", i))}'

RailRoadでRailsのモデルを視覚化(ERDを出す)

RailRoadというライブラリを使うと、Railsのモデルを視覚化することができます。最近のプロジェクトでは先にDBを作ってから実装を始めるというRailsっぽくない開発が多かったので久しくお世話になってなかったのですが、今開発中のアプリはとりあえずモデルの関係だけ定義しておいて、必要になったらフィールドを増やすというラフな開発をしているので、コマンド一発でモデルの関係とフィールドが視覚化できるRailRoadはありがたい存在です。

と、前置きはこのへんにしてUbuntuでRailRoadを使うメモを残しておきます。


Graphvizというクロスプラットフォームの視覚化ツールと、RailRoadのライブラリをインストールします。RailRoadのサイトにはRails1.2.3で動く的なことしか書いてないですが、2.2.2でも動いてます。

sudo aptitude install graphviz
sudo gem install railroad

あとはRailsプロジェクトで、

railroad -M | neato -Tpng > doc/erd.png

すればdoc/erd.pngにERDが出てきます。こんな感じ。

うまくいった!…と思ったら、ERDの表記法がIE表記っぽいんだけど、鳥足の向きが逆…こんな表記法ありましたっけ?IE表記に慣れているのでこれでは見づらい!ということで、向きを逆にしてみる。

railroad -M | sed -e 's/arrowtail=\(.*\)\?, arrowhead=\(.*\)\?,/arrowtail=\2, arrowhead=\1,/g' | neato -Tpng > doc/erd.png

逆になった!

Railsでネストしたリソースのscaffoldを生成する

これは結構便利!blogにひもづくentriesのようなネストしたリソースを管理するアプリを作りたいときに、今まで手動でmodelの関係・routes・controllerのfilter・viewのurlヘルパーをを編集していたが、そこらへんを解決済みのscaffoldを生成してくれるプラグインがあった。

http://deaddeadgood.com/2008/10/8/scaffolding-nested-resources-in-rails

これを使えば、この間作ったRailsで作るログイン可能なブログシステムもたったのこれだけ!

rails blog
cd blog
script/plugin install git://github.com/technoweenie/restful-authentication.git
script/plugin install git://github.com/phorsfall/rspec_on_rails_nested_scaffold.git
script/generate authenticated user
script/generate rspec_nested_scaffold blog title:string user:belongs_to --owner user
script/generate rspec_nested_scaffold entry title:string body:text blog:belongs_to --owner blog
rake db:migrate

で出来ると思ったんだけど、routesとmodelは自分で変更する必要あり。

# config/routes.rb
...
map.resources :users, :shallow => true do |user|
  user.resources :blogs do |blog|
    blog.resources :entries
  end
end
...

# app/models/user.rb
class User < ActiveRecord::Base
  ...
  has_many :blogs
  ...
end

# app/models/blog.rb
class Blog < ActiveRecord::Base
  belongs_to :user
  has_many :entries
end

あとviewからuser:belongs_toとblog:belongs_toの部分を抜いて、ブログとエントリーへのアクセスにログイン必須のフィルターをかけてあげる必要があるけど、こりゃ大分楽になるわ。

追記

routesに:shallow => trueオプションを付けてしまうと、show, editのアクションへのurlを解決できなかった。:shallowオプションなしの一段のネストなら大丈夫。

質問した。

家計簿について。

http://sooda.jp/qa/100720
http://oshiete1.goo.ne.jp/qa4703605.html

始めて人力検索っぽいサービス使ったけど、回答貰えると嬉しい。
Sooda!の回答の早さにびっくりした。回答くださった方ありがとうございます。
引き続きよろしくお願いします。

Cucumberでブログシステムの統合テストをする

バイト先の社内勉強会でCucumberのデモをやったときのログです。

はじめに

このエントリーではCucumberのセットアップから新しいシナリオの追加までの手順を紹介します。エントリーを管理するシンプルなRailsアプリケーションに対するCucumberによるテストを生成し、Feature、Stepの読解とエントリーの変更シナリオの追加を行います。

環境

セットアップ

こちらを参考に。

インストール

Debian/Ubuntuユーザーの人は先にこっちを。

$ sudo apt-get install libxml2-dev libxslt1-dev

必要なRubyのライブラリをインストールします。

$ sudo gem install nokogiri rspec rspec-rails webrat cucumber
依存

矢印の左が右に依存しています。

  • cucumber→webrat
  • webrat→rspecとnokogiri
  • nokogiri→libxmlとlibxslt

ブログシステムを作成

この間作ったマスターは使いません。

タイトルと本分を持つエントリーを管理するシンプルなscaffoldを作成します。

$ rails blog
$ cd blog/
$ script/generate scaffold entry title:string body:text
$ rake db:migrate
$ rake db:migrate RAILS_ENV=test

Cucumberの準備

railsアプリでCucumberを使う準備をします。

$ script/generate cucumber
      create  features/step_definitions
      create  features/step_definitions/webrat_steps.rb
      create  features/support
      create  features/support/env.rb
      create  features/support/paths.rb
      exists  lib/tasks
      create  lib/tasks/cucumber.rake
      create  script/cucumber

シナリオを作成する際に使用する語彙やrakeタスクが生成されます。

エントリー管理のシナリオテストを生成

$ script/generate feature entry title:string body:text
      exists  features/step_definitions
      create  features/manage_entries.feature
      create  features/step_definitions/entry_steps.rb

エントリー管理をテストするための、manage_entries.featureとentry_steps.rbが生成されます。
CucumberではFeatureという自然言語のシナリオと、それをRubyで解釈するためのStepの二つが登場します。詳しくは、Cucumberがアツい - moroの日記

Featureを実行してみる

ジェネレータで生成されたFeatureを実行してみます。

$ rake features
...
2 scenarios
9 steps passed

2つのシナリオと9つのステップが実行されたらしい。では、シナリオがどのようになっているのか見てみましょう。

features/manage_entries.feature
Feature: Manage entries
  In order to [goal]
  [stakeholder]
  wants [behaviour]

  Scenario: Register new entry
    Given I am on the new entry page
    When I fill in "Title" with "title 1"
    And I fill in "Body" with "body 1"
    And I press "Create"
    Then I should see "title 1"
    And I should see "body 1"

  Scenario: Delete entry
    Given the following entries:
      |title|body|
      |title 1|body 1|
      |title 2|body 2|
      |title 3|body 3|
      |title 4|body 4|
    When I delete the 3rd entry
    Then I should see the following entries:
      |title|body|
      |title 1|body 1|
      |title 2|body 2|
      |title 4|body 4|

Scenario:で始まるエントリー登録のシナリオとエントリー削除の2つのシナリオが生成されてますね!どう見てもただの英文テキスト。
Given, When, Then, Andで始まるのがStepでちょうど9つあります。

シナリオとステップの関係

シナリオはステップから構成されていて、シナリオごとに

  1. Given: 前提として○○、
  2. When: そのとき□□すると、
  3. Then: △△になるはず。

という検証を行っています。では、このシナリオはどのように解釈されているんでしょうか。

ここで、ステップ定義の登場です。

features/step_definitions/entry_steps.rb
Given /I am on the new entry page/ do
  visit "/entries/new"
end

Given /^the following entries:$/ do |entries|
  Entry.create!(entries.hashes)
end

When /^I delete the (\d+)(?:st|nd|rd|th) entry$/ do |pos|
  visit entries_url
  within("table > tr:nth-child(#{pos.to_i+1})") do
    click_link "Destroy"
  end
end

Then /^I should see the following entries:$/ do |entries|
  entries.raw[1..-1].each_with_index do |row, i|
    row.each_with_index do |cell, j|
      response.should have_selector("table > tr:nth-child(#{i+2}) > td:nth-child(#{j+1})") { |td|
        td.inner_text.should == cell
      }
    end
  end
end

ステップに対するRubyの命令が書かれています。GivenやThenには/I am on the new entry page/のように正規表現が与えられていて、ステップがこの正規表現にマッチするとブロック内のRubyの命令が実行される仕組みです。

バグがあったときどうなるのか

バグがあるとどうなるのでしょう。
app/views/entries/show.html.erbで本文を出力しているところをコメントアウトしてみます。

app/views/entries/show.html.erb
@@ -5,7 +5,7 @@
 
 <p>
   <b>Body:</b>
-  <%=h @entry.body %>
+  <%#=h @entry.body %>
 </p>

Featureを実行すると、

$ rake features
  Scenario: Register new entry             # features/manage_entries.feature:6
  ...
    And I should see "body 1"              # features/step_definitions/webrat_steps.rb:89
      expected: /body 1/m,
           got: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n
  ...
2 scenarios
8 steps passed
1 step failed
rake aborted!

I should see "body 1"というステップが落ちています。
なるほど、こんな感じで検証できるんですね。app/views/entries/show.html.erbを元に戻して次いってみましょう。

エントリー変更を検証するシナリオを追加する

エントリー登録のシナリオを参考にエントリー変更のシナリオを作成してみます。
シナリオはこんな感じになるはず。

  1. 前提として、id○番のエントリー変更ページを表示していて
  2. かつ、"title 1"と"body 1"が表示されている
  3. そのときTitleに"title updated"と入力して
  4. かつ、Updateボタンを押すと
  5. "title updated"と表示されるはず。

最初から日本語でFeatureを書いておけばよかったと思いつつ、今回は最後まで英語でいきます。


シナリオを追加します。

features/manage_entries.feature
  ...
  Scenario: Register new entry
  ...
  Scenario: Edit existing entry
    Given I am on the edit entry page of 1
    And I should see "title 1"
    And I should see "body 1"
    When I fill in "Title" with "title updated"
    And I press "Update"
    Then I should see "title updated"
  ...
  Scenario: Delete entry

Featureを実行してみます。

$ rake features
...
3 scenarios
9 steps passed
5 steps skipped
1 step pending (1 with no step definition)

1 step pendingということで、新しく追加したGiven I am on the edit entry page of 1 というシナリオがペンディングになっているはずです。解釈できないステップがあるとペンディングになるんですね。


ステップ定義を追加しましょう。idの部分は可変なので変数にします。正規表現の後方参照を使うとブロック引数として受け取ることができます。

features/step_definitions/entry_steps.rb
Given /I am on the edit entry page of (\d+)/ do |id|
  visit "/entries/#{id}/edit"
end

Featureを実行します。

rake features
...
  Scenario: Edit existing entry                  # features/manage_entries.feature:14
    Given I am on the edit entry page of 1       # features/step_definitions/entry_steps.rb:5
      Couldn't find Entry with ID=1 (ActiveRecord::RecordNotFound)
...
3 scenarios
9 steps passed
1 step failed
5 steps skipped
rake aborted!

あれ…落ちましたね。原因はActiveRecord::RecordNotFound。初期データが足りてないんですね。削除のシナリオと同じように初期データを用意しましょう。

最終的なFeatureはこうなります。

features/manage_entries.feature
  ...
  Scenario: Register new entry
  ...
  Scenario: Edit existing entry
    Given the following entries:
      |id|title|body|
      |1|title 1|body 1|
    Given I am on the edit entry page of 1
    And I should see "title 1"
    And I should see "body 1"
    When I fill in "Title" with "title updated"
    And I press "Update"
    Then I should see "title updated"
  ...
  Scenario: Delete entry

今度こそ、Featureを実行すると、

$ rake features
...

3 scenarios
16 steps passed

通った!

試しに、間違ってEntryモデルのタイトルメソッドをオーバーライドすると…

app/models/entry.rb
class Entry < ActiveRecord::Base
  def title
    "title 1"
  end
end
rake features
...
  Scenario: Edit existing entry                  # features/manage_entries.feature:14
    Given the following entries:                 # features/step_definitions/entry_steps.rb:9
    Given I am on the edit entry page of 1       # features/step_definitions/entry_steps.rb:5
    And I should see "title 1"                   # features/step_definitions/webrat_steps.rb:89
    And I should see "body 1"                    # features/step_definitions/webrat_steps.rb:89
    When I fill in "Title" with "title updated"  # features/step_definitions/webrat_steps.rb:18
    And I press "Update"                         # features/step_definitions/webrat_steps.rb:10
    Then I should see "title updated"            # features/step_definitions/webrat_steps.rb:89
      expected: /title updated/m,
...
3 scenarios
14 steps passed
2 steps failed

バッチリおちました!

まとめ

今回はscaffoldに対するシナリオテストを生成し、Cucumberの基本的な使い方を見ていきました。ジェネレータで生成された英語のシナリオをそのまま使いましたが、日本語でシナリオを書くことも可能です。自然言語で書いたシナリオがそのまま動くなんて動く仕様書も夢じゃない!

月々たったの168円でRailsアプリを公開する方法

なんかAdsenseにありそうなタイトルになってしまいましたが(笑)言わずと知れた超高機能で低価格な夢のようなサーバーDream Hostの話です。


Railsでアプリを作ると、作るまではレールに乗っかってすいすい行けるんですが、そこから先の公開となるとPHPのように簡単にはいかないんですよね。


DreamHostを使えば、それが5分で出来てしまいます。(Dream HostというよりPassengerのおかげですけど)しかも、今なら月々たったの168円!金利手数料なし!


円高の今がチャンスということでさっそくサインアップしちゃいました。攻殻のDVDBoxが2000円で買えちゃったりしてるみたいですけど、ほんと円高様様ですね。

スペック

ディスクスペース 50GB+α
転送量 無制限*1
メールアドレス 無制限
ユーザー数 無制限
ドメイン 1個無料
サブドメイン 無制限
開発環境 PHP5, Perl, Python, Ruby(Railsは2.2.2が入ってた!), CSV, SVN

という頭おかしいんじゃないかと思うスペックです。詳しくは、こちら

お値段

月払い$10.95/month, 1年払い$9.95/month 〜 10年払い$5.95/month等のプランがあります。
このままだと1年払いで月1000円くらいですが、promoコードという$97を招待した人とされた人で山分けする仕組みがあり、全額招待された人に配分されているコードがあるので、それを使うと…

$119.4(1年分一括) - $97 = $22.4

2009/2/2現在$1が90円を切ってるので
$22.4 * 90 = ¥2016

つまり月あたり…
¥2016 / 12 = ¥168

ということになるわけです。私もさっそくMax配分のPromoコードを作ったのでぜひ使ってください。


サインアップするときに、

promotion codeに"KOUMIYA"と入力すればおkです。メールアドレスは、配分には関係ないみたいですが、ランキング(?)が出るようなのでめんどくさくなかったら入れてください(笑)

次の画面で割引されているのを確認してくださいね。

使ってみて

安いのには訳がある、その分重いって話も聞きますが今のところ大丈夫です。感覚的なものもあるし、まだ一人でしか使ってないってのでなんとも言えないですが。

さっそくサブドメインを切ってredMineをインストールして使っていますが、かなり快適に使えてます。しかも、チェックボックス1個チェックするだけで、Railsが動く環境が整うのが素晴らしすぎる!とりあえず1年間試してみる価値は十分あると思いますよ。

*1:普通に使っている分には上限なしというニュアンスで、ありえない転送量だったら交渉してねという感じ