日本語・英語の切替の実装

step の追加

Gemfile に capybara-webkit が入っていませんでした。

  gem 'capybara-webkit'

を追加しておきました。

それでは、steps を保存するフォルダを作成します。

mkdir -p spec/acceptance/steps

このフォルダを rspec 時に読み込むように spec_helper.rb に設定します。

Dir.glob("spec/acceptance/steps/*steps.rb") { |f| load f, true }

このフォルダ内に top_page_steps.rb を追加します。

# encoding: utf-8

step 'トップページを表示する' do
  visit '/'
end

step '画面に森高千里データベースと表示されていること' do
  expect(page).to have_content('森高千里データベース')
end

Rspec 内での実行となるので、テスト表記は except().to で記載できます。 このファイルを保存したと同時に Guard によりテストが動作します。

07:25:12 - INFO - Running: spec/acceptance/top_page.feature                     

日本語・英語版の切替を実現する
  日本語のトップページにアクセスする
    トップページを表示する -> 画面に森高千里データベースと表示されていること (FAILED - 1)

Failures:

  1) 日本語・英語版の切替を実現する 日本語のトップページにアクセスする トップページを表示する -> 画面に森高千里データベースと表示されていること
     Failure/Error: ならば 画面に森高千里データベースと表示されていること
     ActionController::RoutingError:
       No route matches [GET] "/"
     # spec/acceptance/steps/top_page_steps.rb:4:in `block in <top (required)>'
     # ./spec/acceptance/top_page.feature:6:in `block (6 levels) in run'
     # ./spec/acceptance/top_page.feature:5:in `each'
     # ./spec/acceptance/top_page.feature:5:in `block (5 levels) in run'
     # -e:1:in `<main>'
     # ./spec/acceptance/top_page.feature:5:in `トップページを表示する'

Finished in 0.01046 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/acceptance/top_page.feature:4 # 日本語・英語版の切替を実現する 日本語のトップページにアクセスする トップページを表示する -> 画面に森高千里データベースと表示されていること

Jenkins のエラーの確認

テストがエラーになったので、Jenkins でエラーが確認できるかどうかをチェックしてみます。steps をリポジトリにコミットすれば、Jenkins が起動してエラーになるはずです。今回、Gemfile を修正したため、bundle のやり直しがありテストに時間がかかりますが、正しく失敗ビルドとなっていることがわかります。

日本語トップページの表示

日本語のトップページを表示するために config/routes.rb に routing 情報を追加します。

  root 'top#index'

このファイルを更新しても Guard テストは実行されないので、guard の画面でリターンキーを叩くとテストが手動起動します。もしくは、以前書いた feature もしくは steps を更新しても Ok です。

  1) 日本語・英語版の切替を実現する 日本語のトップページにアクセスする トップページを表示する -> 画面に森高千里データベースと表示されていること
     Failure/Error: ならば 画面に森高千里データベースと表示されていること
     ActionController::RoutingError:
       uninitialized constant TopController

エラーが代わり、TopController がないというエラーに変わっていることがわかります。generator で top_controller.rb を作成します。

r g controller top

コントローラ、ビューのテストは作成しないことにしていたので、作成されるのは

  • app/controllers/top_controller.rb
  • app/views/top

だけになります。この結果、エラーが以下のように変化します。

     Failure/Error: ならば 画面に森高千里データベースと表示されていること
     AbstractController::ActionNotFound:
       The action 'index' could not be found for TopController

次に app/controllers/top_controller.rb に index メソッドを追加します。

  def index
  end

Guard の結果は以下のように変化します。

     Failure/Error: ならば 画面に森高千里データベースと表示されていること
     ActionView::MissingTemplate:
       Missing template top/index, application/index with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee, :haml]}. Searched in:
         * "/Users/hkob/rails/moritaka-db/app/views"
         * "/Users/hkob/rails/moritaka-db/vendor/bundle/ruby/2.1.0/gems/kaminari-0.15.1/app/views"

index がないと言われるので、app/views/top/index.html.haml を作成します。国際化対応にするため、t メソッドで locales からメッセージを選択するようにします。

%h1=t '.title'

ページを確認すると、ローカライズできていないので、画面には Title としか表示されません。当然ながらテストも通りません。

日本語・英語版の切替を実現する
  日本語のトップページにアクセスする
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
    トップページを表示する -> 画面に森高千里データベースと表示されていること (FAILED - 1)

Failures:

  1) 日本語・英語版の切替を実現する 日本語のトップページにアクセスする トップページを表示する -> 画面に森高千里データベースと表示されていること
     Failure/Error: ならば 画面に森高千里データベースと表示されていること
       expected to find text "森高千里データベース" in "Title"
     # spec/acceptance/steps/top_page_steps.rb:8:in `block in <top (required)>'
     # ./spec/acceptance/top_page.feature:6:in `block (6 levels) in run'
     # ./spec/acceptance/top_page.feature:5:in `each'
     # ./spec/acceptance/top_page.feature:5:in `block (5 levels) in run'
     # -e:1:in `<main>'
     # ./spec/acceptance/top_page.feature:6:in `画面に森高千里データベースと表示されていること'

I18n.enforce_available_locales が将来的に true にセットされるので、validation したくなければ false にセットしておくように警告が出ています。メッセージが出てくるのが面倒なので、config/application.rb に設定しておくことにします。また、ほとんどの人が日本語版を見ると思うので、default_locale は :ja にセットしておきます。

    I18n.enforce_available_locales = true
    config.i18n.default_locale = :ja

さらに、すべてのコントローラで locale を設定するために、app/controllers/application_controller.rb にて before_action を設定します。

  before_action :set_locale
  AVAILABLE_LOCALES = %w(en ja)

  def set_locale
    I18n.locale = params[:locale] || I18n.default_locale
    @is_ja = I18n.locale == :ja
  end

さらに、すべてのリンクに locale オプションが設定されるように default_url_options を設定します。

  def default_url_options(options = {})
    { locale:I18n.locale }
  end

次に locales データを準備します。views の locales データを保存するために、config/locales/views を作成しておきます。

mkdir -p config/locales/views

config/locales/views/ja.yml を記載します。haml において、「.title」と階層を省略したため、locales データは views と同じ階層にしておく必要があります(Rails 3 の I18n についてを参照)。

ja:
  top:
    index:
      title: "森高千里データベース"

この状態で Guard を見るとテストが無事に成功していることがわかります。せっかくなので、コミットして Jenkins でも確認しておきます。

英語版へのリンク

すべてのページに日本語版・英語版への相互リンクを作成します。ページのトップに各メニューへのリンクを載せると共に、相互リンクを掲載することにします。まず、テスト(spec/acceptance/top_page.feature)を修正・追加します。

# encoding: utf-8
# language: ja
機能: 日本語・英語版の切替を実現する
  シナリオ: 日本語のトップページにアクセスする
    前提 トップページを表示する
    ならば 画面に "森高千里データベース" と表示されていること
    
  シナリオ: 英語のトップページに切り替える
    前提 トップページを表示する
    もし "[English]" をクリックする
    ならば 画面に "Chisato Moritaka Database" と表示されていること

  シナリオ: 再度日本語のトップページに切り替える
    前提 トップページを表示する
    もし "[English]" をクリックする
    かつ "[Japanese]" をクリックする
    ならば 画面に "森高千里データベース" と表示されていること

表示する文字列ごとに step を書くのは莫迦らしいので、文字列の部分を変数で指定できるようにします。同様にクリックするリンク名も変数で設定できるようにします。修正後の spec/acceptance/steps/top_page_steps.rb は以下のようになります。

step '画面に :string と表示されていること' do |string|
  expect(page).to have_content(string)        
end                                           
                                              
step ":link をクリックする" do |name|         
  click_link name                             
end                                           

すべてのページにリンクバーを掲載するため、app/views/layouts/application.html.haml に partial で読み込みます。

  %body
    =render partial:'shared/top_link_bar', locals:{ navi:@navi }
    = yield

shared フォルダを作成します。

mkdir -p app/views/shared

app/views/shared/_top_link_bar.html.haml にリンクバーを作成します。体裁はあとあと css で何とかするので、今はとりあえず table でリンクを並べることにします。日本語・英語の相互リンクは recursive_path というメソッドで locale のみを入れ換えることで可能となります。

%table  
  %tr
    %td=link_to lh(t 'link.home'), root_path
    %td              
      -if @is_ja     
        =link_to lh(:English), recursive_path(locale: :en)
      -else          
        =link_to lh(:Japanese), recursive_path(locale: :ja)

recursive_path および lh はすべての view で使えるように app/helpers/application_helper.rb にメソッドを記載します。また、リンク表示は常に lh メソッドを呼ぶことにします。とりあえず、今は名前の前後を大括弧で括ることにします。

module ApplicationHelper
  # 再帰パスを作成
  def recursive_path(options = {})
    request.symbolized_path_parameters.merge(@ids || {}).merge(options)
  end                                       
                                            
  # link 文字列の作成
  def lh(v)
    "[#{v}]"
  end
end

ここまで記述すると、Gaurd も成功しますし、実際の画面でも日本語・英語の切替ができるようになっています。現在のものを heroku にもアップしてみました。取り急ぎ今日はここまで。