概要
概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: The Ultimate Intermediate Ruby on Rails Tutorial: Let’s Create an Entire App!
- 原文公開日: 2017/12/17
- 著者: Domantas G
Rails5中級チュートリアルはセットアップが短めで、RDBMSにはPostgreSQL、テストにはRSpecを用います。
原文が非常に長いので分割します。章ごとのリンクは順次追加します。
注意: Rails中級チュートリアルは、Ruby on Railsチュートリアル(https://railstutorial.jp/)(Railsチュートリアル)とは著者も対象読者も異なります。
目次
- 1. 序章とセットアップ
- 2. レイアウト
- 3. 投稿
- 3-1 認証
- 3-2 ヘルパー
- 3-3 テスト
- 3-4 メインフィード
- 3-5 単一の投稿(本セクション)
- 3-6 特定のブランチ
- 3-7 Service Object
- 3-8 新しい投稿を作成する
- 4. インスタントメッセージ
- 4-1 非公開チャット
- 4-2 連絡先
- 4-3 グループチャット
- 4-4 メッセンジャー
- 5. 通知
- 5-1 つながりリクエスト
- 5-2 チャット
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
パスにアクセスすると、id
が1
の投稿を取得するリクエストが送信されます。
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_selector
やhave_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