rails tutorial 第10章


はじめに

独学でrails tutorialを進めていく過程を投稿していきます。

進めていく上でわからなかった単語、詰まったエラーなどに触れています。

個人の学習のアウトプットなので間違いなどあればご指摘ください。

初めての投稿なので読みにくいところも多々あるかと思いますがご容赦ください。

第10章 ユーザーの更新・表示・削除

10.1.1 編集フォーム

演習2

app/views/users/_form.html.erb
#リスト 10.5: newとeditフォーム用のパーシャル
<%= form_with(model: @user, local: true) do |f| %>
  <%= render 'shared/error_messages', object: @user %>

  <%= 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 %>
  <%= f.password_field :password_confirmation, class: 'form-control' %>

  <%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>

しれっと

object: @user

が追記されています、、、
おそらくshared/error_messagesに渡すオブジェクトを指定しているとは思うのですが
shared/error_messagesは下記のように

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

@userオブジェクトを指定しているから必要ない気がするのですが、、、

参考
https://teratail.com/questions/112178

また、

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

の第2引数が消えています、、、

第2引数はおそらくラベルのテキストだと予想は出来ましたが念のため調べました。

参考
https://teratail.com/questions/112172

第2引数を指定しなくなった事により、ラベルのテキストが
ConfirmationからPassword confirmationと表示されています。

意味はどちらもわかるけれどなぜサイレントで修正されたのか、、、

10.2.3 フレンドリーフォワーディング

Q.
requestオブジェクトって?
A.
request.original_url
現在のリクエストURLを返す
request.get?
HTTPメソッドがGETの時trueを返す

参考
https://railsguides.jp/action_controller_overview.html#request%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88

10.3.2 サンプルのユーザー

問題発生!!
rails db:migrate:resetを実行するとエラーが発生する

Permission denied @ apply2files - C:/environment/sample_app/db/development.sqlite3
Couldn't drop database 'db/development.sqlite3'
rails aborted!
Errno::EACCES: Permission denied @ apply2files - C:/environment/sample_app/db/development.sqlite3
bin/rails:4:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => db:drop:_unsafe
(See full trace by running task with --trace)

こちらの記事を参考に解決しました。
https://qiita.com/Toshiki23/items/f366504844fd22ad87d9

以前参考にしましたね。windowsでは自らがアクセスしているファイルを削除できないようです。

10.3.3 ページネーション

User.paginate(page: 1)

paginateはキー:pageで値ページ番号を取る
User.paginateは、:pageパラメーターに基いて、データベースからひとかたまりのデータ(デフォルトでは30)を取り出す
上のコマンドをコンソールで実行するとページ番号1のオブジェクトを出力します(出力結果が11となりますが、Active Record自身のコンソール上限によるものです。lengthメソッドを呼べばこの制約を回避できます)

@users = User.paginate(page: params[:page])

params[:page])が1なら1~30のユーザー、params[:page])が2なら31~60のユーザーが取り出され@usersに代入されるようになります。
ちなみにページがnilの場合paginateは単に最初のページを返すとのことです。

10.3.5 パーシャルのリファクタリング

app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= will_paginate %>

<ul class="users">
  <% @users.each do |user| %>
    <%= render user %>
  <% end %>
</ul>

<%= will_paginate %>
app/views/users/_user.html.erb
<li>
  <%= gravatar_for user, size: 50 %>
  <%= link_to user.name, user %>
</li>

さらにリファクタリング。

app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= will_paginate %>

<ul class="users">
  <%= render @users %>
</ul>

<%= will_paginate %>

Railsは@users をUserオブジェクトのリストであると推測します。さらに、ユーザーのコレクションを与えて呼び出すと、Railsは自動的にユーザーのコレクションを列挙し、それぞれのユーザーを_user.html.erbパーシャルで出力します。(rails tutorial 10章より引用)

またまた初学者には難しい省略が、、、
コレクション、、、つまり複数のデータのようなものを渡すということでしょうか。

省略出来ることは理解できましたがそうなると_user.html.erbの

app/views/users/_user.html.erb
<li>
  <%= gravatar_for user, size: 50 %>
  <%= link_to user.name, user %>
</li>

eachメソッドで作った変数userはこのままでよいのでしょうか、よいとすれば何をもって変数userという名前に決まったのでしょう?

変数名は何でもよいのでしょうか?
試しに名前を変えてテストをしてみました。

app/views/users/_user.html.erb
<li>
  <%= gravatar_for aaa, size: 50 %>
  <%= link_to aaa.name, user %>
</li>

結果
エラー。

undefined local variable or method `aaa' 

aaaという変数は定義されていないとのこと。

ここまでで推測出来ることは
①render で渡したオブジェクトを単数形にしたものを自動設定している?
②Userクラスのオブジェクトだから同じ名前としたものを自動設定している?

試しに

app/controllers/users_controller.rb
def index
  @aaas = User.paginate(page: params[:page])
end
app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= will_paginate %>

<ul class="users">
  <%= render @aaas %>
</ul>

<%= will_paginate %>

結果

ActionView::Template::Error: The @users variable appears to be empty. Did you forget to pass the collection object for will_paginate?

@users変数が空とのこと。will_paginateにコレクションオブジェクトを渡し忘れていないか?というメッセージも見られました。

ということはコレクションオブジェクトの変数名は@usersとするべきなのでしょうか?

そしてwill_pagineteにもそれ(@usersという名前の付いたコレクションオブジェクト)を渡さなければならないのでしょう、、、多分、、、

railsではUserオブジェクトのコレクションオブジェクトをusersという変数名にする(コレクションオブジェクトはクラスオブジェクトの複数形にする)ことで色々と良しなに解釈してくれる設定があるということでしょうか?

そうすることで変数名をuserとすると、そのコレクションを自動で列挙するといような便利な動作をするとか、、、なので

app/views/users/_user.html.erb
<li>
  <%= gravatar_for user, size: 50 %>
  <%= link_to user.name, user %>
</li>

こうしなければならないのかな?推測ですけれど、、、

色々とよしなに解釈してくれるのは勿論そのためのルールに則った記述をしてこそですからね、、、

終わりに

今回はリファクタリングに悩まされた章でした。
少し曖昧な部分も残してしまったので、何度か振り返り、明確に理解できるよう学習を進めたいです。