0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Rails】ユーザー登録フォームの作成その1【Rails Tutorial 7章まとめ】

Last updated at Posted at 2019-11-27

newアクションとルーティング

ユーザーを新規登録するため、newアクションで新しいUserオブジェクトを作成し、@user変数に入れておく。

app/controllers/users_controller.rb
class UsersController < ApplicationController

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

  def new
    @user = User.new
  end
end

ルーティングはURLを/signupとして、usersコントローラのnewアクションに紐づけておく。

config/routes.rb
Rails.application.routes.draw do
  .
  .
  .
  get  '/signup', to: 'users#new'
  resources :users
end

ユーザー登録フォーム

form_forヘルパーメソッドを使って、ユーザーの新規登録フォームを作る。
form_forはUserオブジェクトを引数にとり、その属性でフォームを生成する。

ユーザー登録フォームは次のようになる。
app/views/users/new.html.erb

app/views/users/new.html
<% 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>

このコードにより生成されるhtmlは次のようになる。

app/views/users/new.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>

form_forを使ったフォームの構造

form_forの役割

form_forは変数fを使ったブロックをとる構造になっており、次のようなhtmlを生成する。

.html
<%= form_for(@user) do |f| %>
  .
  .
  .
<% end %><form accept-charset="UTF-8" action="/users" class="new_user"
      id="new_user" method="post">
  .
  .
  .
</form>

action属性は"/users"、method属性は"post"となっている。
この2つの属性は、/usersに対してHTTPのPOSTリクエストを送信する、といった指示をしている。
すると、Usersリソースが提供するRESTfulなルート(https://qiita.com/kagamiya9/items/48f66b20aee03fe9da1f )に基づいて、createアクションに行き着く。

このような流れが自動でできるのは、次のような理由らしい。
①form_forの引数は@userであり、Railsは@userがUserクラスであることを認識する。
@userはnewアクションで新規作成されているため、Railsはpostメソッドを使ってフォームを構築すべきだと判断する。

各入力フォーム

nameの入力フォームは次のようになる。

.html
<%= f.label :name %>
<%= f.text_field :name %><label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />

emailの入力フォームは次のようになる。

.html
<%= f.label :email %>
<%= f.email_field :email %><label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="email" />

nameのtype属性は"text"だが、emailでは"email"である。
前者はf.text_field、後者はf.email_fieldとすることでtype属性がそれぞれ決まっている。
こうすると、スマホなどではメールアドレス入力用のキーボードが表示されるようになっている。

passwordの入力フォームは次のようになる。

.html
<%= f.label :password %>
<%= f.password_field :password %><label for="user_password">Password</label>
<input id="user_password" name="user[password]" type="password" />

type属性がpasswordの場合、フォームに文字を入力すると黒丸•で表示されるようになる。

password_confiramtionの入力フォームは次のようになる。

.html
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %><label for="user_password_confirmation">Confirmation</label>
<input id="user_password_confirmation"
         name="user[password_confirmation]" type="password" />

password_confirmationでは、f.labelの第二引数に文字列"Confirmation"をとっている。
これにより、フォーム上のラベルが指定した文字列になる。
他のフォームは属性ごとに自動で設定されている。
(nameはNameになる。なお、"Confirmation"を除くと、Password confirmationになる)
サブミットボタンも同様で、value属性が任意の文字列になる。

Createアクションの作成

name属性によるハッシュの構成

.html
<input id="user_name" name="user[name]" - - - />
<input id="user_password" name="user[password]" - - - />

inputには特殊なname属性がついている。
Railsはnameの値を使って、初期化したハッシュを (params変数経由で) 構成する。

どういうことかというと、送信された内容はまず次のようなハッシュになり、params変数に代入される。

.rb
params = { users: { name: "Foo Bar", email: "foo@invalid", 
           password: "foo", password_confirmation: "bar" } }

createアクションでは、このparams変数を使ってユーザーを新規登録する。

.rb
@user = User.new(params[:user])

:userシンボルの値は、入力される属性(nameやemail)とその値からなるハッシュなので、上のコードは次のコードと同じである。

.rb
@user = User.new(name: "Foo Bar", email: "foo@invalid",
                 password: "foo", password_confirmation: "bar")

Strong Parameters

上のようなコードはセキュリティ上問題があるらしい。
paramsをそのまま送信すると、管理者用の属性であるadminなどの値を送信して、管理者権限を奪われるからだとか。
この辺は説明が非常に分かりにくいのだが、要は許可された属性以外は送信できないようにする、ということだ。

結局のところ、次のようなuser_paramsメソッドをコントローラ内に作る。
これはStrong Parametersと呼ばれる。
先の問題があるコードは、マスアサイメントと呼ばれる。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  .
  .
  .
  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
end

private内にあるメソッドはweb経由で外部に晒されることがない。

ユーザー登録に失敗した場合の処理

ユーザー登録に失敗した場合は、renderメソッドを使って新規登録ページに戻り、エラーメッセージを表示する。
エラー部分は長いので別記事にまとめることにする。

ユーザー登録に成功した場合の処理

成功部分も別記事にまとめることにする。

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?