マイクロポストを作成する
Micropostsコントローラのcreateアクション
app/controllers/microposts_controller.rb
class MicropostsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
# create,destroyを行う前にログインを求めらえれる。
def create
@micropost = current_user.microposts.build(micropost_params)
# 慣習的に関連するモデルを生成するときは、buildを使う
if @micropost.save
flash[:success] = "Micropost created!"
redirect_to root_url
# redirect_to は、view の表示には直接は関係なく、新たな HttpRequest が発行されます。
else
render 'static_pages/home'
# action で view を指定しない場合、規約に従って、リソース名 や
# action名を元に、表示する view が決まります。
end
end
def destroy
end
private
def micropost_params
params.require(:micropost).permit(:content)
# マイクロポストのcontentカラムだけ取り出すことができる。
end
end
Homeページ(/)にマイクロポストの投稿フォームを追加する
app/views/static_pages/home.html.erb
<% if logged_in? %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
</div>
<% else %>
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>
<%#= image_tag("kitten.jpg", alt: "Kitten") %>
<%= link_to image_tag("rails.svg", alt: "Rails logo", width: "200px"),
"https://rubyonrails.org/" %>
サイドバーで表示するユーザー情報のパーシャル
app/views/shared/_user_info.html.erb
<%= link_to gravatar_for(current_user, size: 50), current_user %>
<!--グラバターの画像と何か-->
<h1><%= current_user.name %></h1>
<!--ユーザー名-->
<span><%= link_to "view my profile", current_user %></span>
<!--リンクとリンク先-->
<!--current_user とは権限のチェックに使われるユーザー識別子-->
<span><%= pluralize(current_user.microposts.count, "micropost") %></span>
<!--マイクロポストの数を表示する-->
<!--例 3micropost-->
マイクロポスト投稿フォームのパーシャル
app/views/shared/_micropost_form.html.erb
<%= form_with(model: @micropost, local: true) do |f| %>
<!--local: trueがない場合、Rails5ではAjaxによる送信という意味になる。
普通にHTMLとしてフォームを送信する場合にlocal: trueが必要になる-->
<!--マイクロポストをHTMLのフォームとして一つずつ取り出す-->
<%= render 'shared/error_messages', object: f.object %>
<!--sharedフォルダのerror_messagesを表示させる。-->
<!--object: f.objectでは、f.objectに@userが入っている-->
<!--object: f.objectはerror_messagesパーシャルの中でobjectという変数名を
作成してくれるので、この変数を使って
エラーメッセージを更新すればよいということです-->
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost..." %>
<!--コメント欄を作ることができる-->
<!--その欄にコメントを書いておく-->
</div>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
homeアクションにマイクロポストのインスタンス変数を追加する
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
@micropost = current_user.microposts.build if logged_in?
# ログインされたら current_userのマイクロポストを生成する
end
def help
end
def about
# aboutアクションを作成
end
def contact
end
end
Userオブジェクト以外でも動作するようにerror_messagesパーシャルを更新する
app/views/shared/_error_messages.html.erb
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(object.errors.count, "error") %>.
<!--@user.errors.countはエラーの回数-->
<!--pluralizeは引数が出力される-->
<!--エラーの回数と"error"の文字列が表示される-->
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
テスト
ubuntu:~/environment/sample_app (user-microposts) $ rails t
Running via Spring preloader in process 9841
Started with run options --seed 3594
ERROR["test_password_resets", #<Minitest::Reporters::Suite:0x0000558f7e479e20 @name="PasswordResetsTest">, 3.4448097949998555]
test_password_resets#PasswordResetsTest (3.45s)
ActionView::Template::Error: ActionView::Template::Error: undefined local variable or method `object' for #<#<Class:0x0000558f7df2a370>:0x0000558f7e3a5fd0>
Did you mean? object_id
app/views/shared/_error_messages.html.erb:1
app/views/password_resets/edit.html.erb:8
app/views/password_resets/edit.html.erb:6
test/integration/password_resets_test.rb:49:in `block in <class:PasswordResetsTest>'
ERROR["test_should_get_home", #<Minitest::Reporters::Suite:0x0000558f7e66cc50 @name="StaticPagesControllerTest">, 3.56740082899978]
test_should_get_home#StaticPagesControllerTest (3.57s)
ActionView::SyntaxErrorInTemplate: ActionView::SyntaxErrorInTemplate: Encountered a syntax error while rendering template: check <% if logged_in? %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
</div>
<% else %>
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>
<%#= image_tag("kitten.jpg", alt: "Kitten") %>
<%= link_to image_tag("rails.svg", alt: "Rails logo", width: "200px"),
"https://rubyonrails.org/" %>
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
test/controllers/static_pages_controller_test.rb:19:in `block in <class:StaticPagesControllerTest>'
ERROR["test_should_get_root", #<Minitest::Reporters::Suite:0x0000558f7ec0bb98 @name="StaticPagesControllerTest">, 3.6514615249998315]
test_should_get_root#StaticPagesControllerTest (3.65s)
ActionView::SyntaxErrorInTemplate: ActionView::SyntaxErrorInTemplate: Encountered a syntax error while rendering template: check <% if logged_in? %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
</div>
<% else %>
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>
<%#= image_tag("kitten.jpg", alt: "Kitten") %>
<%= link_to image_tag("rails.svg", alt: "Rails logo", width: "200px"),
"https://rubyonrails.org/" %>
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
test/controllers/static_pages_controller_test.rb:12:in `block in <class:StaticPagesControllerTest>'
ERROR["test_login_with_valid_email/invalid_password", #<Minitest::Reporters::Suite:0x0000558f7dd5b9b8 @name="UsersLoginTest">, 4.065607392999937]
test_login_with_valid_email/invalid_password#UsersLoginTest (4.07s)
ActionView::SyntaxErrorInTemplate: ActionView::SyntaxErrorInTemplate: Encountered a syntax error while rendering template: check <% if logged_in? %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
</div>
<% else %>
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>
<%#= image_tag("kitten.jpg", alt: "Kitten") %>
<%= link_to image_tag("rails.svg", alt: "Rails logo", width: "200px"),
"https://rubyonrails.org/" %>
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
test/integration/users_login_test.rb:19:in `block in <class:UsersLoginTest>'
ERROR["test_login_with_valid_information_followed_by_logout", #<Minitest::Reporters::Suite:0x0000558f7e082740 @name="UsersLoginTest">, 4.221937290999904]
test_login_with_valid_information_followed_by_logout#UsersLoginTest (4.22s)
ActionView::SyntaxErrorInTemplate: ActionView::SyntaxErrorInTemplate: Encountered a syntax error while rendering template: check <% if logged_in? %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
</div>
<% else %>
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>
<%#= image_tag("kitten.jpg", alt: "Kitten") %>
<%= link_to image_tag("rails.svg", alt: "Rails logo", width: "200px"),
"https://rubyonrails.org/" %>
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
test/integration/users_login_test.rb:45:in `block in <class:UsersLoginTest>'
ERROR["test_layout_links_when_logged_in", #<Minitest::Reporters::Suite:0x0000558f7edf52b0 @name="SiteLayoutTest">, 4.905898562999937]
test_layout_links_when_logged_in#SiteLayoutTest (4.91s)
ActionView::SyntaxErrorInTemplate: ActionView::SyntaxErrorInTemplate: Encountered a syntax error while rendering template: check <% if logged_in? %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
</div>
<% else %>
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>
<%#= image_tag("kitten.jpg", alt: "Kitten") %>
<%= link_to image_tag("rails.svg", alt: "Rails logo", width: "200px"),
"https://rubyonrails.org/" %>
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
test/integration/site_layout_test.rb:29:in `block in <class:SiteLayoutTest>'
ERROR["test_layout_links", #<Minitest::Reporters::Suite:0x0000558f7c452b60 @name="SiteLayoutTest">, 4.953971497999646]
test_layout_links#SiteLayoutTest (4.95s)
ActionView::SyntaxErrorInTemplate: ActionView::SyntaxErrorInTemplate: Encountered a syntax error while rendering template: check <% if logged_in? %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
</div>
<% else %>
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>
<%#= image_tag("kitten.jpg", alt: "Kitten") %>
<%= link_to image_tag("rails.svg", alt: "Rails logo", width: "200px"),
"https://rubyonrails.org/" %>
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
app/views/static_pages/home.html.erb:28: syntax error, unexpected end-of-input, expecting end
test/integration/site_layout_test.rb:6:in `block in <class:SiteLayoutTest>'
56/56: [===========================] 100% Time: 00:00:04, Time: 00:00:04
Finished in 4.96300s
56 tests, 265 assertions, 0 failures, 7 errors, 0 skips
ActionView::Template::Error: ActionView::Template::Error: undefined local variable or method `object'
ActionView::SyntaxErrorInTemplate: ActionView::SyntaxErrorInTemplate: Encountered a syntax error while rendering template: check <% if logged_in? %>
と書かれている。
objectがおかしいのがわかる、その次がわからない
このパーシャルは他の場所でも使われていたため、ユーザー登録、パスワード再設定、そしてユーザー編集のそれぞれのビューを更新する必要があったのです。
ユーザー登録時のエラー表示を更新する
app/views/users/new.html.erb
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(model: @user, local: true) do |f| %>
<!--一つずつ取り出す-->
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
ユーザー編集時のエラー表示を更新する
app/views/users/edit.html.erb
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(model: @user, local: true) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Save changes", class: "btn btn-primary" %>
<% end %>
<div class="gravatar_edit">
<%= gravatar_for @user %>
<a href="https://gravatar.com/emails">change</a>
</div>
</div>
</div>
パスワード再設定時のエラー表示を更新する
app/views/password_resets/edit.html.erb
<% provide(:title, 'Reset password') %>
<h1>Reset password</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(model: @user, url: password_reset_path(params[:id]),
local: true) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= hidden_field_tag :email, @user.email %>
<!--隠しフィールドとしてページ内に保存する手法をとります。-->
<!--フォームを送信した後使用するメアドが消えてしまうので
ここに保存させる。-->
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Update password", class: "btn btn-primary" %>
<% end %>
</div>
</div>
演習
1.Homeページをリファクタリングして、if-else文の分岐のそれぞれに対してパーシャルを作ってみましょう。
home.html.erb
<% if logged_in? %>
<%= render 'static_pages/user_logged_in' %>
<% else %>
<%= render 'static_pages/user_not_logged_in' %>
<% end %>
user_logged_in.html.erb
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= render 'shared/user_info' %>
</section>
<section class="micropost_form">
<%= render 'shared/micropost_form' %>
</section>
</aside>
</div>
user_not_logged_in.html.rb
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>
<%= link_to image_tag("rails.svg", alt: "Rails logo", width: "200px"),
'http://rubyonrails.org/' %>
2.
マイクロポストを投稿した直後に、ブラウザの更新ボタンを押すとエラーが表示されます。なぜエラーが表示されるのでしょうか?その原因を考えてみましょう。
わからない。
3.
もし上記の現象に対応するとしたら、どんな対応方法があるでしょうか?その対応方法を考えてみましょう。(ヒント: 様々な対応方法がありますが、対応方法によっては今後の実装に支障が出ることがあります。ここでは対応方法のアイデア出しに留めておきましょう。)
わからない。