Ruby on Rails Tutorial (19)

朝練メモ。最近盛り込みが複雑になってきたのもあるけれど、ミスが多い。

10.3 Manipulating microposts

microposts の routing は作るか消すしかない模様。config/routes.rb に以下を追加な模様。

  resources :microposts, only: [:create, :destroy]

で、保存して確認。

$ bundle exec 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
   sessions POST   /sessions(.:format)       sessions#create
new_session GET    /sessions/new(.:format)   sessions#new
    session DELETE /sessions/:id(.:format)   sessions#destroy
 microposts POST   /microposts(.:format)     microposts#create
  micropost DELETE /microposts/:id(.:format) microposts#destroy
       root        /                         static_pages#home
     signup        /signup(.:format)         users#new
     signin        /signin(.:format)         sessions#new
    signout DELETE /signout(.:format)        sessions#destroy
       help        /help(.:format)           static_pages#help
      about        /about(.:format)          static_pages#about
    contact        /contact(.:format)        static_pages#contact

知らない間にこんなに育っちまった。

10.3.1 Access control

signin してないと作成および削除はできない、と。当り前ですね。それを試験する spec が以下になるのかな。
spec/requests/authentication_pages_spec.rb (一部のみ)

      describe "in the Microposts controller" do

        describe "submitting to the create action" do
          before { post microposts_path }
          specify { response.should redirect_to(signin_path) }
        end

        describe "submitting to the destroy action" do
          before { delete micropost_path(FactoryGirl.create(:micropost)) }
          specify { response.should redirect_to(signin_path) }
        end
      end

上記は "for non-signed-in users" なブロックの中に置かれます。のでリダイレクトされるべき、なんですね。試験は当然 red 終了。試験パスにもってくにはちょっとした refactoring が必要、ってありますね。
ええと users_controller.rb にある signed_in_user メソドを app/helpers/session_helper.rb 方面に持ってけ、ということなのかな。
これで microposts な controller でもこのメソドが呼び出せる、ということなのか。before_filter に盛り込んでおけば

  def signed_in_user
    unless signed_in?
      store_location
      redirect_to signin_url, notice: "Please sign in."
    end
  end

signin なソレにリダイレクトされる、と。つうか microposts_controller.rb が無いな。面倒なのでそのまま作るか。

class MicropostsController < ApplicationController
  before_filter :signed_in_user, only: [:create, :destroy]

  def index
  end

  def create
  end

  def destroy
  end
end

これで試験実行。green 終了確認。

10.3.2 Creating microposts

投稿関連。ユーザ登録で似たようなことしてるよね、とのこと。とりあえず試験を作成。

$ rails generate integration_test micropost_pages
      invoke  rspec
      create    spec/requests/micropost_pages_spec.rb

で、以下を盛り込み。
spec/requests/micropost_pages_spec.rb

require 'spec_helper'

describe "MicropostPages" do
  subject { page }
  
  let(:user) { FactoryGirl.create(:user) }
  before { sign_in user }

  describe "micropost creation" do
    before { visit root_path }

    describe "with invalid information" do

      it "should not create a micropost" do
        expect { click_button "Post" }.not_to change(Micropost, :count)
      end

      describe "error messages" do
        before { click_button "Post" }
        it { should have_content('error') }
      end
    end

    describe "with valid information" do

      before { fill_in 'micropost_content', with: "Lorem ipsum" }
      it "should create a micropost" do
        expect { click_button "Post" }.to change(Micropost, :count).by(1)
      end
    end
  end
end

ええと、よくよく見るに subject とかって確認した方が良いですね。visit root_path とかも若干微妙。この場合は入力画面になるのかどうか。つうかやっぱ全部盛り込み終わった時点で全部ざくっと確認しないとマズいですね。理解が微妙な部分が多すぎる。ざっくりは理解できてるんですがorz
試験保存して red 終了確認。
controller 方面に 10.30 を盛り込みます。

  def create
    @micropost = current_user.microposts.build(params[:micropost])
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      render 'static_pages/home'
    end
  end

試験パスするまで道が長いですが盛り込んでみます。

  • app/views/static_pages/home.html.erb
  • app/views/shared/_user_info.html.erb
  • app/views/shared/_micropost_form.html.erb
  • app/controllers/static_pages_controller.rb
  • app/views/shared/_error_messages.html.erb

ここで以下が green との記述あり。がしかし red 終了。ちょい時間切れなので別途確認の方向でエントリは投入しときます。対処などおそらく追記されるはず。

追記

app/views/shared/_error_messages.html.erb の盛り込み漏れが原因でした。@user.errors な記述が残っておりました。でもまだ試験 red ですね。
あ、原因は typo でした。とほほ。試験 green 確認してます。
残りもう少しなのでそのまま盛り込み続行。

  • app/views/users/new.html.erb
  • app/views/users/edit.html.erb

これらは両方 render 'shared/error_messages' してる箇所ですね。
これで全ての試験が green 終了のはず。green 終了でした。よかった。

$ bundle exec rspec spec/
Rack::File headers parameter replaces cache_control after Rack 1.5.
.............................................................................................................
                             
Finished in 35.92 seconds
109 examples, 0 failures

Randomized with seed 15328

さらに追記

エントリを改めるのもアレなのでそのまま続けて、ということにて。

10.3.3 A proto-feed

ええと、自分の feed を表示させるのか。w3m だと mock 見ながら云々できなくてちょい不便。user model に feed というメソドが追加になるんですかね。あら、follow が云々という話が出てきてますね。とりあえず Listing 10.38 な試験を盛り込んでおきます。

  • feed という属性 (メソド) があること
  • フォローしていないユーザのポストは feed に含まれないこと

つうか

    describe "status" do
      let(:unfollowed_post) do
        FactoryGirl.create(:micropost, user: FactoryGirl.create(:user))
      end

な記述が色々と微妙なんですがorz
あと、include は配列なオブジェクトのメソドなんすね。で、_とりあえず_ feed なメソドは以下な記述に、とのこと。id はちゃんとエスケイプする手段があるはずなんですが、ここでは_とりあえず_なのだろうな。

  def feed
    # This is preliminary. See "Following users" for the full implementation.
    Micropost.where("user_id = ?", id)
  end

上記盛り込んで試験実行してみましたが、green 終了してしまいました。以降順次盛り込んでいきたいと思います。

  • spec/requests/static_pages_spec.rb
    • root_path にアクセスしたら feed なコンテンツが出てること
  • app/controllers/static_pages_controller.rb
    • signed_in? なら feed 表示の用意
  • app/views/shared/_feed.html.erb
  • app/views/shared/_feed_item.html.erb
    • こいつが id 付きの li を吐いてるのか
  • app/views/static_pages/home.html.erb
  • app/controllers/microposts_controller.rb
    • 保存に失敗した場合、@feed_items に [] を代入

これで試験 green になるはず、とありますがどうなのか。つうか盛り込んだだけなんだけどこれで良いのか(とは言え、ざっくりは理解できてますが)。
試験 green は確認済みです。

10.3.4 Destroying microposts

この節で 10 は終わりらしいのでそのまま続けてみます。最後に削除を実装して終わりな模様。削除なリンクは投稿者のみ、という形なのかな。
とりあえず partial なソレについて削除リンクを追加してます。

  • app/views/microposts/_micropost.html.erb
  • app/views/shared/_feed_item.html.erb

この試験は spec/requests/micropost_pages_spec.rb で以下を追加とのこと。

  describe "micropost destruction" do
    before { FactoryGirl.create(:micropost, user: user) }

    describe "as correct user" do
      before { visit root_path }

      it "should delete a micropost" do
        expect { click_link "delete" }.to change(Micropost, :count).by(-1)
      end
    end
  end

試験的には signin 前提になっております、念の為。

$ bundle exec rspec spec/requests/micropost_pages_spec.rb

あら、red 終了だな。controller にも盛り込みが必要なのかな。そもそも destroy というメソドが空でした。
app/controllers/microposts_controller.rb に before_filter 追加して

class MicropostsController < ApplicationController
  before_filter :signed_in_user, only: [:create, :destroy]
  before_filter :correct_user,   only: :destroy

必要なメソドの記述を追加。

  def destroy
    @micropost.destroy
    redirect_to root_url
  end

  private

    def correct_user
      @micropost = current_user.microposts.find_by_id(params[:id])
      redirect_to root_url if @micropost.nil?
    end

ぐ、また試験 red だな。以下が NG な模様。

    describe "with valid information" do

      before { fill_in 'micropost_content', with: "Lorem ipsum" }
      it "should create a micropost" do
        expect { click_button "Post" }.to change(Micropost, :count).by(1)
      end
    end
  end

  describe "micropost destruction" do
    before { FactoryGirl.create(:micropost, user: user) }

    describe "as correct user" do
      before { visit root_path }

      it "should delete a micropost" do
        expect { click_link "delete" }.to change(Micropost, :count).by(-1)
      end
    end
  end

ん、_feed_item.html.erb?
コピペで済ませてて以下になってましたorz

  <% if current_user?(micropost.user) %>
    <%= link_to "delete", micropost, method: :delete,
                                     data: { confirm: "You sure?" },
                                     title: micropost.content %>
  <% end %>

正しくは以下。

  <% if current_user?(feed_item.user) %>
    <%= link_to "delete", feed_item, method: :delete,
                                     data: { confirm: "You sure?" },
                                     title: feed_item.content %>
  <% end %>

とほほ杉orz
試験 green 確認してます。

後始末

git および heroku へのナニを云々。
ちなみに heroku pg:reset ができませんでした。いっかいアプリを削除して再度 push とかしてみようかな。

確認必要なソレ

  • request な試験に出てくる subject について