Tech Racho エンジニアの「?」を「!」に。
  • 開発

Rails5「中級」チュートリアル(3-5)投稿機能: 単一の投稿(翻訳)

概要

概要

原著者の許諾を得て翻訳・公開いたします。

Rails5中級チュートリアルはセットアップが短めで、RDBMSにはPostgreSQL、テストにはRSpecを用います。
原文が非常に長いので分割します。章ごとのリンクは順次追加します。

注意: Rails中級チュートリアルは、Ruby on Railsチュートリアル(https://railstutorial.jp/)(Railsチュートリアル)とは著者も対象読者も異なります。

目次

Rails5「中級」チュートリアル(3-5)投稿機能: 単一の投稿(翻訳)

新しいブランチに切り替えます。

git checkout -b single_post

単一の投稿を表示する

現時点では、show.html.erbテンプレートやそれに対応するコントローラアクションがないので、I'm interestedボタンをクリックするとエラーが表示されます。このボタンをクリックしたら、選択した投稿のページにリダイレクトされるようにしたいと思います。

PostsControllerの内部にshowアクションを作成します。ここでクエリをかけて特定のpostオブジェクトをインスタンス変数に保存します(Gist)。

# controllers/posts_controller.rb
  def show
    @post = Post.find(params[:id])
  end

I'm interestedボタンは、選択した投稿へのリダイレクトを行います。このボタンのhref属性には投稿へのパスが保存されます。投稿を1件取得するためのGETリクエストを送信すると、Railsはshowアクションを呼び出します。このshowアクションの中ではidパラメータ(params)にアクセスします。このidは、特定の投稿を1件取得するためのGETリクエストからのものです。たとえば、ブラウザで/posts/1パスにアクセスすると、id1の投稿を取得するリクエストが送信されます。

portsディレクトリの下にshow.html.erbテンプレートを作成します。

views/posts/show.html.erb

このファイルに以下のコードを追加します(Gist)。

<!-- views/posts/show.html.erb -->
<div id="single-post-content" class="container">
  <div class="row">
    <div class="col-sm-6 col-sm-offset-3">
      <div class="posted-by">Posted by <%= @post.user.name %></div>
      <h3><%= @post.title %></h3>
      <p><%= @post.content %></p>
    </div>
  </div><!-- row -->
</div>

postsディレクトリの下にshow.scssファイルを作成し、以下のCSSを追加してページのスタイルを整えます(Gist)。

// assets/stylesheets/partials/posts/show.scss
#single-post-content {
  background: white;
  height: calc(100vh - 50px);

  h3 { 
    text-align: center;
  }
  p {
    margin: 50px 0;
  }
  .posted-by {
    font-size: 12px;
    font-size: 1.2rem;
    margin: 20px 0;
    color: rgba(0,0,0,0.5);
  }
}

ここではページの高さを100vh-50pxで定義しているので、ページのコンテンツの高さはビューポート(viewport)の高さいっぱいになります。これにより、要素内のコンテンツの量が多くても少なくても、このコンテナの色はブラウザの高さいっぱいまで白になります。vhは「ビューポートの高さ」を表すので、100vhという値を指定すると要素はビューポートの高さの100%まで引き伸ばされます。ナビゲーションバーの高さを100vh-50pxから引いておく必要があります。そうしておかないと、コンテナの高さが50px余分に伸びてしまいます。

これで、I'm interestedボタンをクリックするとページがリダイレクトされて以下のように表示されます。

show.html.erbテンプレートには後で他にも機能を追加しますので、今は変更をcommitしておきましょう。

git add -A
git commit -m "Create a show template for posts

- Add a show action and query a post to an instance variable
- Create a show.scss file and add CSS"

spec

こういうモーダルウインドウや選択した投稿のリダイレクトといった機能が正常に動くかどうかのチェックは、手動で行わず、すべてspecに含めておきましょう。capybaraを使ってユーザーのアプリ操作をシミュレートすることにします。

featuresディレクトリの下にpostsディレクトリを作成します。

spec/features/posts

このディレクトリにvisit_single_post_spec.rbファイルを作成し、feature specをそこに追加します。追加後のファイルは以下のようになります(Gist)。

# spec/features/posts/visit_single_post_spec.rb
require "rails_helper"

RSpec.feature "Visit single post", :type => :feature do
  let(:user) { create(:user) }
  let(:post) { create(:post) }

  scenario "User goes to a single post from the home page", js: true do
    post
    visit root_path
    page.find(".single-post-card").click
    expect(page).to have_selector('body .modal')
    page.find('.interested a').click
    expect(page).to have_selector('#single-post-content p', text: post.content)
  end

end

ここでは、手動での操作手順をすべて定義しています。最初にhomeページを開き、投稿をクリックすると、モーダルウインドウがポップアップすることを期待(expect)しています。I'm interestedボタンをクリックすると、投稿ページにリダイレクトしてコンテンツが表示されることを期待しています。

RSpecのhave_selectorhave_cssなどのマッチャーは、ある要素がユーザーに実際に見える状態になっているとデフォルトでtrueを返します。したがって、投稿でクリックした後にテスティングフレームワークはモーダルウインドウが表示されることを期待します。ある要素がユーザーに見えるかどうかは問題でない場合や、要素がDOMにあるかどうかだけを知りたい場合は、visible: false引数を追加します。

テストを実行してみましょう。

rspec spec/features/posts/visit_single_post_spec.rb

変更をcommitします。

git add -A
git commit -m "Add a feature spec to test if a user can go to a
single post from the home page"

single_postブランチをmasterにmergeします。

git checkout master
git merge single_post
git branch -D single_post

関連記事

新しいRailsフロントエンド開発(1)Asset PipelineからWebpackへ(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。