Ruby on Rails Tutorial (8)

ちょっとフライングで前の晩から着手してますが。

7.2 Signup form

とりあえずデータベースをリセットとのこと。

$ bundle exec rake db:reset
$ bundle exec rake db:test:prepare
7.2.1 Tests for user signup

とりあえず以下な試験が fail なことを確認してみます。
spec/requests/user_pages_spec.rb

require 'spec_helper'

describe "User pages" do

  subject { page }
  .
  .
  .
  describe "signup" do

    before { visit signup_path }

    let(:submit) { "Create my account" }

    describe "with invalid information" do
      it "should not create a user" do
        expect { click_button submit }.not_to change(User, :count)
      end
    end

    describe "with valid information" do
      before do
        fill_in "Name",         with: "Example User"
        fill_in "Email",        with: "user@example.com"
        fill_in "Password",     with: "foobar"
        fill_in "Confirmation", with: "foobar"
      end

      it "should create a user" do
        expect { click_button submit }.to change(User, :count).by(1)
      end
    end
  end
end

で、試験実行。

$ bundle exec rspec spec/request/

試験 red を確認。上書きしてなくて green 確認したのはヒミツ。

Failures:

  1) User pages signup with invalid information should not create a user
     Failure/Error: expect { click_button submit }.not_to change(User, :count)
     Capybara::ElementNotFound:
       no button with value or id or text 'Create my account' found
     # (eval):2:in `click_button'
     # ./spec/requests/user_pages_spec.rb:30:in `block (5 levels) in <top (required)>'
     # ./spec/requests/user_pages_spec.rb:30:in `block (4 levels) in <top (required)>'

  2) User pages signup with valid information should create a user
     Failure/Error: fill_in "Name",         with: "Example User"
     Capybara::ElementNotFound:
       cannot fill in, no text field, text area or password field with id, name, or label 'Name' found
     # (eval):2:in `fill_in'
     # ./spec/requests/user_pages_spec.rb:36:in `block (4 levels) in <top (required)>'

ふむ。成程。

7.2.2 Using form_for

app/views/users/new.html.erb を以下にとのこと。

<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="span6 offset3">
    <%= form_for(@user) do |f| %>

      <%= f.label :name %>
      <%= f.text_field :name %>

      <%= f.label :email %>
      <%= f.text_field :email %>

      <%= f.label :password %>
      <%= f.password_field :password %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation %>

      <%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
    <% end %>
  </div>
</div>

これを盛り込んで試験実行してみます。以下な方法が提示されています。

$ bundle exec rspec spec/requests/user_pages_spec.rb -e "signup page"

試験 red 終了。controller にも盛り込みが必要な模様。確かに new なアクションは空ですね。

  def new
    @user = User.new
  end

これで試験を再度実行してみると green 終了してました。むむむ。
app/assets/stylesheets/custom.css.scss に以下を盛り込んで次の項に進みます。

/* forms */

input, textarea, select, .uneditable-input {
  border: 1px solid #bbb;
  width: 100%;
  padding: 10px;
  margin-bottom: 15px;
  @include box_sizing;
}

input {
  height: auto !important;
}

一応、見栄えがどうかを確認しようと思ったのですが、突如端末が暴走。再起動して WEBrick 起動して確認してみました。結構無茶な使い方してるはずなのでアレ。
/signup と /users/new の違いは何なのか別途確認。
あと WEBrick は使わないときはオトしておかないと端末が暴走するのかどうなのか。
7.2.3 The form HTML はスルーで次に。

7.3 Signup failure

以下は失敗する試験なのかな。

$ bundle exec rspec spec/requests/user_pages_spec.rb \
> -e "signup with invalid information"

以下で試験 red ですね。良いのかな。

Failures:

  1) User pages signup with invalid information should not create a user
     Failure/Error: expect { click_button submit }.not_to change(User, :count)
     AbstractController::ActionNotFound:
       The action 'create' could not be found for UsersController
     # (eval):2:in `click_button'
     # ./spec/requests/user_pages_spec.rb:30:in `block (5 levels) in <top (required)>'
     # ./spec/requests/user_pages_spec.rb:30:in `block (4 levels) in <top (required)>'

ええと rake routes 確認してみると

$ rake routes
    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
 new_user GET    /users/new(.:format)      users#new
edit_user GET    /users/:id/edit(.:format) users#edit
     user GET    /users/:id(.:format)      users#show
          PUT    /users/:id(.:format)      users#update
          DELETE /users/:id(.:format)      users#destroy

/users で POST すると users#create が云々なのか。なので controller にアクション追加してるんですね。

  def create
    @user = User.new(params[:user])
    if @user.save
      # Handle a successful save.
    else
      render 'new'
    end
  end

アクション追加したらさきほどの試験がどうなるかというと green 終了しました。実行されてる試験は以下。

    let(:submit) { "Create my account" }

    describe "with invalid information" do
      it "should not create a user" do
        expect { click_button submit }.not_to change(User, :count)
      end
    end
7.3.2 Signup error messages

エラーメセジ出漁用途として app/views/users/new.html.erb を以下な形に。

<div class="row">
  <div class="span6 offset3">
    <%= form_for(@user) do |f| %>
      <%= render 'shared/error_messages' %>

で、partial なソレも用意。
app/views/shared/_error_messages.html.erb

<% if @user.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-error">
      The form contains <%= pluralize(@user.errors.count, "error") %>.
    </div>
    <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li>* <%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

M-x make-directory Enter Enter って知らなんだ (何
それは良いとしてこれで @user.errors.any? の時に上の partial が出力される形になっているはず。試験も green です。

$ bundle exec rspec spec/requests/user_pages_spec.rb \
> -e "signup with invalid information"

見栄え確認してみます。て、エラーメセジが出ねぇと思ったら new.html.erb を上書きしていませんでした。無事出力を確認。

7.4 Signup success

登録成功した時のソレを盛り込む、ということになるのか。

7.4.1 The finished signup form

とりあえず試験実行。

$ bundle exec rspec spec/requests/user_pages_spec.rb \
> -e "signup with valid information"

red 確認。

Failures:

  1) User pages signup with valid information should create a user
     Failure/Error: expect { click_button submit }.to change(User, :count).by(1)
     ActionView::MissingTemplate:
       Missing template users/create, application/create with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in:
         * "/home/rms/OLDHome/rms/Documents/rails_proj/sample_app/app/views"
     # (eval):2:in `click_button'
     # ./spec/requests/user_pages_spec.rb:43:in `block (5 levels) in <top (required)>'
     # ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in <top (required)>'

controller に処理を盛り込んでいませんので当り前。create アクションを以下にせよ、とのこと。

  def create
    @user = User.new(params[:user])
    if @user.save
      redirect_to @user
    else
      render 'new'
    end
  end

これで試験は all green になる模様。

$ bundle exec rspec spec/

all green 確認。すばらです。

7.4.2 The flash

flash というのも昔からある仕組みですね。app/views/layouts/application.html.erb 方面に以下を盛り込みなさいとのこと。

  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <% flash.each do |key, value| %>
        <div class="alert alert-<%= key %>"><%= value %></div>
      <% end %>
      <%= yield %>
      <%= render 'layouts/footer' %>
      <%= debug(params) if Rails.env.development? %>
    </div>

container なクラスの div な部分の中の flash.each なブロックか。で、登録成功時に情報出力と。
app/controllers/users_controller.rb

  def create
    @user = User.new(params[:user])
    if @user.save
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
  end
7.4.3 The first signup

ユーザ一件登録。Rails Tutorial/example@railstutorial.org で良いのかな。登録直後には flash が出力されて reload したら消える模様。確認 OK です。

7.4.4 Deploying to production with SSL

ここまでのソレで commit を作って master に merge してますね。

$ git add .
$ git commit -m "Finish user signup"
$ git checkout master
$ git merge sign-up --no-ff

で、Heroku 方面でも云々してます。config/environments/production.rb な以下の部分を有効にするのかな。

  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  # config.force_ssl = true

で、master ブランチに commit を作って

$ git commit -a -m "Add SSL in production"

Heroku 方面に push か。

$ git push heroku

deploy しているご様子。ちょっと時間かかってます。以下なコマンドも叩けとのこと。

$ heroku run rake db:migrate

で、heroku open とか heroku log とか出てますね。確かに signup にアクセスしたら https になってました。わははは。heroku logs も情報満載ですね。
別途余裕があれば exercise にも手を出してみようと思います。