Ruby on Rails Tutorial (38)

controllers な試験ですが、relationship_controller 向けのみなのか。relationship なソレについては create と destroy というアクションのみ、な定義。--format documentation で試験実行してみます。

$ bundle exec rspec spec/controllers/relationships_controller_spec.rb --format documentation
WARNING: Nokogiri was built against LibXML version 2.7.8, but has dynamically loaded 2.8.0
Rack::File headers parameter replaces cache_control after Rack 1.5.

RelationshipsController
  creating a relationship with Ajax
    should increment the Relationship count
    should respond with success
  destroying a relationship with Ajax
    should decrement the Relationship count
    should respond with success

Finished in 2.3 seconds
4 examples, 0 failures

Randomized with seed 17898

あらら、ここの試験面白いな。テキスト的には 11.2.5 のあたりか。テキスト確認しつつメモを控える方向にて。

  • form_for に remote: true を付けれ、という記述あり
  • 試験がいきなり全部出てるな
  • 実は controller の試験の最初の例
  • xhr メソド
    • 使われる HTTP メソドを symbol で指定
    • アクションを symbol で指定
    • パラメータを渡す
  • Ajax な request では Rails は自動的にアクションな名前の .js.erb なファイルを云々とありますね
    • app/views/relationships 配下に {destroy, create}.js.erb があります
    • JQuery がなんちゃら、とあるな
  • 何から表示されてるのかを忘れている件
    • _{follow, unfollow}.html.erb は _follow_form.html.erb から render されている
    • _follow_form.html.erb は show.html.erb からナニ
    • {create, destroy}.js.erb は更新対象のソレを記述している模様。。。むむむ。

例えば app/views/relationships/create.js.erb だと以下な記述になってて

$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= @user.followers.count %>')

ええと app/views/users/_follow_form.html.erb について以下なソレについて

  <% if current_user.following?(@user) %>
    <%= render 'unfollow' %>
  <% else %>
    <%= render 'follow' %>
  <% end %>

users/unfollow な partial を render してね、という意味なのか。あるいは二行目の followers ってのは何を指すのかな。む、app/vieww/shared/_stats.html.erb の followers というクラスってことなのか。むむむむ。なんかおかしい気がするんだけど基本的にはナチュラルな勘違いなんだろうなorz
ええと、そうか。あるユーザの profile てきな画面を表示しててその人を follow/unfollow するから follower なカウントが変わるのか。成程。

change というメソド

以下な記述、あまり詳細な解説が無いな。

  describe "creating a relationship with Ajax" do

    it "should increment the Relationship count" do
      expect do
        xhr :post, :create, relationship: { followed_id: other_user.id }
      end.to change(Relationship, :count).by(1)
    end

Relationship なオブジェクトの count が 1 増えている (change?) ことを expect という話になるのかどうなのか。unfollow な試験は以下な記述。

    it "should decrement the Relationship count" do
      expect do
        xhr :delete, :destroy, id: relationship.id
      end.to change(Relationship, :count).by(-1)
    end

今、ip unreachable なのでアレなんですが別途確認の方向ってことで。

spec/request 配下確認着手

authentication_pages_spec.rb から。順に見ていくんですが先頭が以下なカンジ。

describe "Authentication" do

  subject { page }

  describe "signin page" do
    before { visit signin_path }

    it { should have_selector('h1',    text: 'Sign in') }
    it { should have_selector('title', text: 'Sign in') }
  end

page の意味は別途確認。文脈的に page should have_selector な確認してますね。signin_path なソレは以下か。

        signin        /signin(.:format)              sessions#new

出力されるのは app/views/sessions/new.html.erb なのでその記述に関する確認、という形になるのか。確かに title なソレも h1 なナニも Sign in ですね。

<% provide(:title, "Sign in") %>
<h1>Sign in</h1>

あるいは以降のブロックで何を確認しているのか、というと

  describe "signin" do
    before { visit signin_path }

    describe "with invalid information" do
      before { click_button "Sign in" }

      it { should have_selector('title', text: 'Sign in') }
      it { should have_error_message('Invalid') }
      
      describe "after visiting another page" do
        before { click_link "Home" }
        it { should_not have_selector('div.alert.alert-error') }
      end    
    end

sessions#new からいきなり Sign in なボタンをクリックしてるのか。ええと app/views/sessions/new.html.erb は以下な定義になってて

    <%= form_for(:session, url: sessions_path) do |f| %>

ええと sessions_path は以下ですね。

      sessions POST   /sessions(.:format)            sessions#create

sessions#create なアクションになるのか。sign in 失敗時には

      flash.now[:error] = 'Invalid email/password combination'

というソレが、なので 'Invalid' という error message が、という事か。あるいは alert とか alert-error な div は app/views/shared/_error_messages.html.erb で以下。

    <div class="alert alert-error">

これ、shared/error_messages を render してないこと、をナニしてるのか。ええと、Home なリンクを click してるので app/views/static_pages/home.html.erb が出るとして、例えばログインに成功してれば shared/micropost_form が render されるんですが

<% if signed_in? %>
  <div class="row">
    <aside class="span4">
      <section>
        <%= render 'shared/user_info' %>
      </section>
      <section>
        <%= render 'shared/stats' %>
      </section>
      <section>
        <%= render 'shared/micropost_form' %>
      </section>

shared/micropost_form の定義が以下で

<%= form_for(@micropost) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>

うーん、ちょっとよく分からないので rails s してみました。sign in 失敗して Home に行くと当り前なのですが shared/error_messages は無関係ですね。
んーと、shared/error_messages な記述があるのは

  • sign-up
  • updating-showing-and-deleting-users
  • user-micropost

あたりなのか。なんとなく微妙なところにひっかかってる気がしてならないのでスルーするか。や、Invalid な flash のソース部分見てみるに以下。

    <div class="container">
        <div class="alert alert-error">Invalid email/password combination</div>
      <h1>Sign in</h1>

成程ッスね。Home リンク踏んだら flash も消えてること、が確認したかったのか。次は以下。ちょっと分かりにくいですが以下のソレも、なはず。

  describe "signin" do
    before { visit signin_path }

で、以下。

    describe "with valid information" do
      let(:user) { FactoryGirl.create(:user) }

      before { sign_in user }

これで user で sign_in できる模様。このあたりのテキストな記述も再度確認したいな。で、sign_in した後の挙動 (というかプレゼンテーション) を確認して

      it { should have_selector('title', text: user.name) }

      it { should have_link('Users', href: users_path ) }
      it { should have_link('Profile', href: user_path(user)) }
      it { should have_link('Settings', href: edit_user_path(user)) }
      it { should have_link('Sign out', href: signout_path) }

      it { should_not have_link('Sign in', href: signin_path) }

sign out 時の挙動も確認してますね。

      describe "followed by signout" do
        before { click_link "Sign out" }
        it { should have_link('Sign in') }
      end
    end
  end

む、

      before { sign_in user }

て何、って思ったんですが、app/helpers/sessions_helper.rb で sign_in てメソドを定義してるんですね。この SessionHelper は

module SessionsHelper

  def sign_in(user)

application_controller で include されている模様。む、view 側でも current_user とか使ってらっしゃいますが、コントローラの属性は view 側からアクセスできるのか。なんつーか知らんことばっかだな。

宿題

  • expect do ... end.to change なあたりの確認
  • subject { page } な記述について確認