LoginSignup
0
0

More than 3 years have passed since last update.

Railsチュートリアル:7章

Posted at

7章。ユーザー編続き。

まずはいつも通り、ブランチ作成。

git checkout -b sign-up

リスト 7.1: サイトのレイアウトにデバッグ情報を追加する
app/views/layouts/application.html.erb

<%= debug(params) if Rails.env.development? %>

追加。

リスト 7.2: デバッグ表示を整形するための追加と、Sassのミックスイン.
app/assets/stylesheets/custom.scss


@mixin box_sizing {
  -moz-box-sizing:    border-box;
  -webkit-box-sizing: border-box;
  box-sizing:         border-box;
}
/* miscellaneous */

.debug_dump {
  clear: both;
  float: left;
  width: 100%;
  margin-top: 45px;
  @include box_sizing;
}

追加。

dbに6章で登録したユーザーがきちんといるのかを検証。

ec2-user:~/environment/sample_app (sign-up) $ rails console
Running via Spring preloader in process 4656
Loading development environment (Rails 5.1.6)
>> User.count
   (0.1ms)  SELECT COUNT(*) FROM "users"
=> 1
>> User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2020-05-05 05:02:56", updated_at: "2020-05-05 05:02:56", password_digest: "$2a$10$zjzfkvsimhFwLB0RuXRQxOIOZSQTyUUyPYabuX7sU37...">

リスト 7.3: Usersリソースをroutesファイルに追加する
config/routes.rb

ユーザーそれぞれのページのルーティング設定。

resources :users

追加。

リスト 7.4: ユーザー情報を表示するための仮のビュー
app/views/users/show.html.erb

手動でビューを作成

<%= @user.name %>, <%= @user.email %>

インスタンス変数があることを前提にしているらしい。

リスト 7.5: Usersコントローラのshowアクション
app/controllers/users_controller.rb

def show
    @user = User.find(params[:id])
  end

追加。

伝家の宝刀params[:id]

説明は、、、
ユーザーのid読み出しにはparamsを使いました。Usersコントローラにリクエストが正常に送信されると、params[:id]の部分はユーザーidの1に置き換わります。つまり、この箇所は6.1.4で学んだfindメソッドの User.find(1)と同じになります。(技術的な補足: params[:id]は文字列型の "1" ですが、findメソッドでは自動的に整数型に変換されます)。

安定のさらっと。

実際に/users/1ページにアクセス。

すると説明が。

デバッグ情報からparams[:id]の値を確認できることを確認してください (図 7.6)。


action: show
controller: users
id: '1'
このid: '1'は /users/:id から取得した値です。この値を使って

User.find(params[:id])
上のコードでid=1のユーザーを検索できる、といった仕組みになっているのです

いや、まずデバックってなんなのかしらんし。

リスト 7.6: debuggerをUsersコントローラに差し込む
app/controllers/users_controller.rb

debugger

追加。

/users/1 にアクセス

504 Gateway Time-outとでる。

ターミナルをみると

[1, 10] in /home/ec2-user/environment/sample_app/app/controllers/users_controller.rb
    1: class UsersController < ApplicationController
    2: 
    3:   def show
    4:     @user = User.find(params[:id])
    5:     debugger
=>  6:   end
    7: 
    8:   def new
    9:   end
   10: end
(byebug) 

どうやらページはみれないが、続きはできそうである
ビビッて調べたら↓のサイトが
https://rakuda3desu.net/rakudas-rails-tutoria7-1/

(byebug) @user.name
"Michael Hartl"
(byebug) @user.email
"mhartl@example.com"
(byebug) params[:id]
"1"
(byebug)   Rendering users/show.html.erb within layouts/application
  Rendered users/show.html.erb within layouts/application (0.7ms)
  Rendered layouts/_shim.html.erb (0.3ms)
  Rendered layouts/_header.html.erb (0.9ms)
  Rendered layouts/_footer.html.erb (0.6ms)
Completed 200 OK in 291161ms (Views: 293.1ms | ActiveRecord: 0.7ms)

ターミナル上で作業だけしました。

リスト 7.7: debuggerをUsersコントローラーから取り外す
app/controllers/users_controller.rb

class UsersController < ApplicationController

  def show
    @user = User.find(params[:id])
  end

  def new
  end
end

デバッガー削除

今後Railsアプリケーションの中でよく分からない挙動があったら、上のようにdebuggerを差し込んで調べてみましょう。トラブルが起こっていそうなコードの近くに差し込むのがコツです。byebug gemを使ってシステムの状態を調査することは、アプリケーション内のエラーを追跡したりデバッグするときに非常に強力なツールになります。

とのこと。イミフ。

もう一度、users/1にアクセスしてみた。

元通りアクセスできた。よかった。

リスト 7.8: ユーザー表示ビューに名前とGravatarを表示する
app/views/users/show.html.erb

<% provide(:title, @user.name) %>
<h1>
  <%= gravatar_for @user %>
  <%= @user.name %>
</h1>

書き換え。

リスト 7.9: gravatar_forヘルパーメソッドを定義する
app/helpers/users_helper.rb

module UsersHelper

  # 引数で与えられたユーザーのGravatar画像を返す
  def gravatar_for(user)
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
    image_tag(gravatar_url, alt: user.name, class: "gravatar")
  end
end

追加。

dbの登録情報を変える指示。

ec2-user:~/environment/sample_app (sign-up) $ rails console
Running via Spring preloader in process 5981
Loading development environment (Rails 5.1.6)
>> user = User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2020-05-05 05:02:56", updated_at: "2020-05-05 05:02:56", password_digest: "$2a$10$zjzfkvsimhFwLB0RuXRQxOIOZSQTyUUyPYabuX7sU37...">
>> user.update_attributes(name: "Example User",
?> ?>                        email: "example@railstutorial.org",
?> ?>                        password: "foobar",
?> ?>                        password_confirmation: "foobar")
Traceback (most recent call last):
SyntaxError ((irb):3: syntax error, unexpected tIDENTIFIER, expecting =>)
?>                        email: "example@railstutorial.org",
                          ^~~~~
>> user.update_attributes(name: "Example User",
?> ?>                        email: "example@railstutorial.org",
?> ?>                        password: "foobar",
?> ?>                        password_confirmation: "foobar")
Traceback (most recent call last):
SyntaxError ((irb):7: syntax error, unexpected tIDENTIFIER, expecting =>)
?>                        email: "example@railstutorial.org",
                          ^~~~~
(irb):7: syntax error, unexpected ',', expecting end
...l: "example@railstutorial.org",
...                              ^
(irb):8: syntax error, unexpected ',', expecting end
...            password: "foobar",
...                              ^
(irb):9: syntax error, unexpected ')', expecting end
...assword_confirmation: "foobar")
...                              ^

エラー祭り。

いろいろ試すと、

コンソールに打ち込む

user.update_attributes(name: "Example User",
?> email: "example@railstutorial.org",
?> password: "foobar",
?> password_confirmation: "foobar")

この2~4行目を一気にコピーして打ち込むとダメで一行ずつコピーしてやるといけた。

>> user.update_attributes(name: "Example User",
?> email: "example@railstutorial.org",
?> password: "foobar",
?> password_confirmation: "foobar")
   (0.1ms)  begin transaction
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) AND ("users"."id" != ?) LIMIT ?  [["email", "example@railstutorial.org"], ["id", 1], ["LIMIT", 1]]
  SQL (3.9ms)  UPDATE "users" SET "name" = ?, "email" = ?, "updated_at" = ?, "password_digest" = ? WHERE "users"."id" = ?  [["name", "Example User"], ["email", "example@railstutorial.org"], ["updated_at", "2020-05-05 08:06:29.274815"], ["password_digest", "$2a$10$dlKmj98ZLEtoQwRbrtM.QOBPvndZXRMfo889DsWvmGHOb8bj/J6vO"], ["id", 1]]
   (6.2ms)  commit transaction
=> true

リスト 7.10: ユーザーのshowビューにサイドバーを追加する
app/views/users/show.html.erb

<% provide(:title, @user.name) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <h1>
        <%= gravatar_for @user %>
        <%= @user.name %>
      </h1>
    </section>
  </aside>
</div>

変更

リスト 7.11: SCSSを使ってサイドバーなどのユーザー表示ページにスタイルを与える
app/assets/stylesheets/custom.scss

/* sidebar */

aside {
  section.user_info {
    margin-top: 20px;
  }
  section {
    padding: 10px 0;
    margin-top: 20px;
    &:first-child {
      border: 0;
      padding-top: 0;
    }
    span {
      display: block;
      margin-bottom: 3px;
      line-height: 1;
    }
    h1 {
      font-size: 1.4em;
      text-align: left;
      letter-spacing: -1px;
      margin-bottom: 3px;
      margin-top: 0px;
    }
  }
}

.gravatar {
  float: left;
  margin-right: 10px;
}

.gravatar_edit {
  margin-top: 15px;
}

追加。

リスト 7.14: newアクションに@user変数を追加する
app/controllers/users_controller.rb

def new
    @user = User.new
  end

追加

リスト 7.15: 新規ユーザーのためのユーザー登録フォーム
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_for(@user) do |f| %>
      <%= f.label :name %>
      <%= f.text_field :name %>

      <%= f.label :email %>
      <%= f.email_field :email %>

      <%= f.label :password %>
      <%= f.password_field :password %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

リスト 7.16: ユーザー登録フォームのCSS
app/assets/stylesheets/custom.scss
※さきこっちらしい

/* forms */

input, textarea, select, .uneditable-input {
  border: 1px solid #bbb;
  width: 100%;
  margin-bottom: 15px;
  @include box_sizing;
}

input {
  height: auto !important;
}

リスト 7.17: 図 7.12のフォームのHTMLソース

<form accept-charset="UTF-8" action="/users" class="new_user"
      id="new_user" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input name="authenticity_token" type="hidden"
         value="NNb6+J/j46LcrgYUC60wQ2titMuJQ5lLqyAbnbAUkdo=" />
  <label for="user_name">Name</label>
  <input id="user_name" name="user[name]" type="text" />

  <label for="user_email">Email</label>
  <input id="user_email" name="user[email]" type="email" />

  <label for="user_password">Password</label>
  <input id="user_password" name="user[password]"
         type="password" />

  <label for="user_password_confirmation">Confirmation</label>
  <input id="user_password_confirmation"
         name="user[password_confirmation]" type="password" />

  <input class="btn btn-primary" name="commit" type="submit"
         value="Create my account" />
</form>

確認しました。

リスト 7.18: ユーザー登録の失敗に対応できるcreateアクション
app/controllers/users_controller.rb

class UsersController < ApplicationController

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])    # 実装は終わっていないことに注意!
    if @user.save
      # 保存の成功をここで扱う。
    else
      render 'new'
    end
  end
end

書き換え

リスト 7.19: createアクションでStrong Parametersを使う
app/controllers/users_controller.rb

def create
    @user = User.new(user_params)
    if @user.save
      # 保存の成功をここで扱う。
    else
      render 'new'
    end
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end

書き換え。

ここは完全にプロゲートとは違います。

エラーメッセージに関して

>> user = User.new(name: "Foo Bar", email: "foo@invalid",
?> password: "dude", password_confirmation: "dude")
=> #<User id: nil, name: "Foo Bar", email: "foo@invalid", created_at: nil, updated_at: nil, password_digest: "$2a$10$WvMnxBE8Pzi8VitiprtRzugUhSsJMWT0oP9DFA57R1N...">
>> user.save
   (0.1ms)  begin transaction
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ?  [["email", "foo@invalid"], ["LIMIT", 1]]
   (0.1ms)  rollback transaction
=> false
>> user.errors.full_messages
=> ["Email is invalid", "Password is too short (minimum is 6 characters)"]

リスト 7.20: ユーザー登録失敗時にエラーメッセージが表示されるようにする
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_for(@user) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= 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>

sharedがでてきたのでまたそれをつくる。

もうこの辺は感覚でしかわからん。

mkdir app/views/shared

リスト 7.21: フォーム送信時にエラーメッセージを表示するためのパーシャル
app/views/shared/_error_messages.html.erb

<% if @user.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(@user.errors.count, "error") %>.
    </div>
    <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

演習があるけどうまくいきません

ec2-user:~/environment/sample_app (sign-up) $ rails console

Running via Spring preloader in process 7727
Loading development environment (Rails 5.1.6)
>> 
>> user.errors.count
Traceback (most recent call last):
        1: from (irb):2
NameError (undefined local variable or method `user' for main:Object)
Did you mean?  super
>> 
ec2-user:~/environment/sample_app (sign-up) $ rails console
Running via Spring preloader in process 7751
Loading development environment (Rails 5.1.6)
>> user.errors.count
Traceback (most recent call last):
        1: from (irb):1
NameError (undefined local variable or method `user' for main:Object)
Did you mean?  super
>> user.errors.empty?
Traceback (most recent call last):
        2: from (irb):2
        1: from (irb):2:in `rescue in irb_binding'
NameError (undefined local variable or method `user' for main:Object)
>> user.errors.any?
Traceback (most recent call last):
        2: from (irb):3
        1: from (irb):3:in `rescue in irb_binding'
NameError (undefined local variable or method `user' for main:Object)

もうこのままいく。

ここでなぞの演習

>> helper.pluralize(1, "error")
=> "1 error"
>> helper.pluralize(5, "error")
=> "5 errors"
>> helper.pluralize(2, "woman")
=> "2 women"
>> helper.pluralize(3, "erratum")
=> "3 errata"

複数形になるらしい。

リスト 7.22: エラーメッセージにスタイルを与えるためのCSS
app/assets/stylesheets/custom.scss

#error_explanation {
  color: red;
  ul {
    color: red;
    margin: 0 0 30px 0;
  }
}

.field_with_errors {
  @extend .has-error;
  .form-control {
    color: $state-danger-text;
  }
}

追加

ページアクセスして、同じ内容いれてみた。

The form contains 4 errors.
Email is invalid
Password can't be blank
Password can't be blank
Password is too short (minimum is 6 characters)

エラーがひとつおおい&重複

なぞだけど進む。

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