LoginSignup
0
0

More than 1 year has passed since last update.

railsチュートリアル第十三章 マイクロポストを作成する

Posted at

マイクロポストを作成する

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.
もし上記の現象に対応するとしたら、どんな対応方法があるでしょうか?その対応方法を考えてみましょう。(ヒント: 様々な対応方法がありますが、対応方法によっては今後の実装に支障が出ることがあります。ここでは対応方法のアイデア出しに留めておきましょう。)

わからない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0