【Rails】i18n で日本語化する方法

目次

はじめに

i18nというデフォルトでRailsに同梱されているgemを使ってRailsアプリを日本語化しました。

ここでいう日本語化というのは、ビューファイルには日本語を記述せずにブラウザ上の表示は日本語になっていることを指します。

具体例を手を動かしながら進めると理解の助けになるかと思います。

実装

実装手順は大まかに次の通りです。

  1. Railsのアプリケーション設定
  2. (モデルとコントローラー、ビューを作成)
  3. 辞書ファイルの作成( ja.yml )
  4. ビューを辞書から参照するように書き換える

Railsアプリを新しく作成します。

$ rails new i18n_practice

Railsのアプリケーション設定

config/application.rbにデフォルトで日本語の辞書を読み込むように設定します。また、読み込む辞書ファイルをconfig/locales/配下の全てのrb, ymlファイルに設定します。

次の2行を追加します。

config.i18n.default_locale = :ja
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module I18nPractice
  class Application < Rails::Application
    config.load_defaults 5.2

    config.i18n.default_locale = :ja
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]

  end
end

モデルとコントローラー、ビューを作成

モデルとコントローラーを作成します。

$ rails g model user name:string email:string password:string
...
$ rails g controller users index new
...

テーブルを作成します。

$ rails db:migrate

ルーティング設定とビューを編集します。

ルーティングにルートへのアクセスを追加し、あとでform_withヘルパーを使うときに楽なのでリソースルーティングにします。

Rails.application.routes.draw do
  root 'users#index'
  resources :users, only: %i[index new]
end

ビューを次のように編集します。

<h1>Users#index</h1>

<p>インデックス</p>
<p>サッカー</p>
<p>銀行</p>

<%= form_with model: @user, local: true do |form|  %>
  <div>
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>
  <div>
    <%= form.label :email; %>
    <%= form.email_field :email %>
  </div>
  <div>
    <%= form.label :password %>
    <%= form.password_field :password %>
  </div>
  <div>
    <%= form.submit '送信' %>
  </div>
<% end %>

<div><%= link_to 'new', new_user_path %></div>
<h1>Users#new</h1>

<p>新しい</p>
<p>野球</p>
<p>川岸</p>

<%= form_with url: "#", local: true do |form|  %>
  <div>
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>
  <div>
    <%= form.label :email; %>
    <%= form.email_field :email %>
  </div>
  <div>
    <%= form.label :password %>
    <%= form.password_field :password %>
  </div>
  <div>
    <%= form.submit '送信' %>
  </div>
<% end %>

<div><%= link_to 'index', users_path %></div>

現時点での表示は次の通りです。

f:id:aoshota:20201003115016p:plain
コードに日本語を記述しているindexビュー
f:id:aoshota:20201003115221p:plain
コードに日本語を記述しているnewビュー

コードを見てわかるように今は直接日本語をコードに書いています。これをi18nを使ってコードに日本語は書かず、辞書ファイルを用意することにより同じ表示を実装します。

辞書ファイルの作成( ja.yml )

辞書ファイルを作成します。辞書ファイルはconfig/locales配下に配置します。

デフォルトでconfig/localesにen.ymlがありますがこれは使わないので削除します。

config
└── locales
   ├── activerecord
   │   └── ja.yml
   └── views
       └── ja.yml

lazy lookup記法で簡潔に辞書ファイルを記述することができます。

activerecord/ja.ymlにはモデルに関連することを記述しviews/ja.ymlにはビューに関連することを記述します。

モデルに関する辞書を読み込むことでform_withヘルパーなどでモデルのインスタンス変数を渡した際に自動で紐つけて日本語化してくれます。

ja:
  activerecord:
    models:
      user: ユーザー
    attributes:
        user:
          id: ID
          name: 名前
          email: メールアドレス
          password: パスワード
  attributes:
    created_at: 作成日
    updated_at: 更新日

コントローラーやアクションを越えて使うような単語はdefaultsなどにまとめて設定すると便利です。

ja:
  defaults:
      send: 送信
  users:
    index:
      index: インデックス
      soccer: サッカー
      bank: 銀行
    new:
      new: 新しい
      baseball: 野球
      bank: 川岸

ビューを辞書から参照するように書き換える

i18nのtranslateメソッドを使うことにより辞書を読みんで多言語化することができます。

埋め込みRubyでは次のように実装します。

<%= translate '.title' %>

translateメソッドは省略することもできます。

<%= t '.title' %>

今回のビューファイルは次のように書き換えることができます。

form_withヘルパーにモデルのインスタンス変数を渡している場合はモデルに関する辞書を自動に読み込んでくれます。

<h1>Users#index</h1>

<p><%= translate '.index'  %></p>
<p><%= t '.soccer' %></p>
<p><%= t '.bank' %></p>

<%= form_with model: @user, local: true do |form|  %>
  <div>
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>
  <div>
    <%= form.label :email; %>
    <%= form.email_field :email %>
  </div>
  <div>
    <%= form.label :password %>
    <%= form.password_field :password %>
  </div>
  <div>
    <%= form.submit (t 'defaults.send') %>
  </div>
<% end %>

<div><%= link_to 'new', new_user_path %></div>

form_withヘルパーにURLを渡している場合、明示的にモデルを指定することにより読み込む辞書を判断してくれます。

<h1>Users#new</h1>

<p><%= translate '.new' %></p>
<p><%= t '.baseball' %></p>
<p><%= t '.bank' %></p>

<%= form_with url: "#", local: true do |form|  %>
  <div>
    <%= form.label :name, User.human_attribute_name(:name) %>
    <%= form.text_field :name %>
  </div>
  <div>
    <%= form.label :email, User.human_attribute_name(:email) %>
    <%= form.email_field :email %>
  </div>
  <div>
    <%= form.label :password, User.human_attribute_name(:password) %>
    <%= form.password_field :password %>
  </div>
  <div>
    <%= form.submit (t 'defaults.send') %>
  </div>
<% end %>

<div><%= link_to 'index', users_path %></div>

これでコードに日本語表記はないですが、ブラウザの表示は日本語化されています。

f:id:aoshota:20201003130002p:plain
コードに日本語表記がないindexビュー
f:id:aoshota:20201003130039p:plain
コードに日本語表記がないnewビュー

まとめ

辞書ファイルを作成しビューのコードに直接日本語を記述しない方法を実装しました。

用途に沿ってファイル分割をすることにより可読性もメンテナンス性も上がると思います。

なので、なるべく日本語化(多言語化)は辞書ファイルから読み込む方法で実装するべきだと感じました。

rails-i18nといったgemを使うと一般的な用語(エラーや単位など)は多数の言語に対応できるようなので時間があるときに触ってみたいと思います。

終わりに

最初は理解が難しかったですが手を動かしているうちに理解できるようになりました。

Railsの便利さには日々驚かされます。

参考文献

Railsのシンプルなログイン機能 Part3

目次

はじめに

 ログイン機能の勉強として機能を細分化しつつ実装します。

 理解するための実装なので設計上好ましくない実装が含まれます。できるだけシンプルに実装し、理解し易さを求めたので今回のような実装になりました。ないとは思いますが、後述するコードを参考にする際はお気をつけください。

  • 環境
バージョン
OS OS X 10.15.6
ruby 2.6.4
rails 6.0.3

 前回の続きをやっていきます。前回はパスワードの暗号化や登録情報のバリデーションを実装しました。それに次の項目を加えます。

  1. ユーザー編集
  2. ユーザー削除

設計

  • データベース
カラム 用途 データ型
id 自動生成のID intger
name ユーザーネーム string
password_digest パスワード string
  • 機能(追加)

    1. ユーザー編集機能

    2. ユーザー削除機能

  • ビュー

ファイル名 内容
index.html.erb ユーザー一覧
new.html.erb 登録画面
edit.html.erb 編集画面

実装

ユーザー編集機能の追加

編集をする時の流れは以下の通りです。

① ユーザー一覧の編集したいユーザーの編集ボタンを押す。

ルーターによりeditアクションが実行され編集ページにリダイレクトされる。
(この時、編集したいユーザーの情報がインスタンス変数として渡される。)

③ ユーザー情報を編集し、更新ボタンを押す。

ルーターによりupdateアクションが実行され成功すればユーザー一覧にリダイレクトし、失敗したら編集ページにエラー表示をする

  • ルーティングの設定

次のようにルーティングを設定します。

Rails.application.routes.draw do
  get 'users/index'
  get 'users/new'
  get 'users/home'
  get '/users/create', to: 'users#new'
  post '/users/create'
  get '/user/:id/edit', to: 'users#edit', as: 'edit_users'
  patch '/users/:id', to: 'users#update'

  root 'users#index'
end

as: 'edit_users'も追加していることによりedit_users_pathヘルパーが使えるようになります。

  • viewの編集

ユーザー一覧に編集ボタンを追加します。

<h1>ユーザー一覧</h1>
<%= link_to '登録画面へ', '/users/new' %>
<table>
  <tr>
    <th>ユーザー名</th>
  </tr>

  <% @users.each do |user| %>
  <tr>
    <td><%= user.name %></td>
    <td><%= link_to 'Edit', edit_users_path(user) %></td>
  </tr>
  <% end %>
</table>

rails server を起動してユーザー一覧ページの編集ボタンを開発ツールで見るとリンク先が<a href="/user/5/edit">Edit</a>のようにレンダリングされているのがわかります。

  • editアクションの追加

コントローラーを次のように変更します。

class UsersController < ApplicationController
  def index
     @users = User.all
  end

  def new
    @user = User.new
  end

  def home
  end

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

  def create
    @user = User.new(user_params)

    if @user.save
      redirect_to '/users/index'
    else
      render '/users/new'
    end
  end

  private
    def user_params
      params.require(:user).permit(:name, :password, :password_cofirmation)
    end
end

edit用のviewファイルも追加します。登録ページ(new.html.erb)を少し変えたものになります。

<h1>ユーザー編集</h1>
<%= link_to 'ユーザー一覧', '/users/index' %>
<form action="/users/<%= params[:id] %>" method="post">
<input type="hidden" name="_method" value="patch">
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
  <ul>
    <li>
      <label for="user_name">Name:</label>
      <input type="text" id="user_name" name="user[name]" value="<%= @user.name %>">
    </li>
    <li>
      <label for="user_password">Password:</label>
      <input type="password" id="user_password" name="user[password]">
    </li>
    <li>
      <label for="user_password">Password(confirm):</label> 
 
     <input type="password" id="user_password_confirmation" name="user[password_confirmation]">
    </li>
    <li>
      <input type="submit" value="編集">
    </li>
  </ul>
</form>

追加した1行は<input type="hidden" name="_method" value="patch">です。 また、名前入力欄には編集前の名前を表示するためにinputタグのvalue属性をvalue="<%= @user.name %>"にしています。フォームの送信先<form action="/users/<%= params[:id] %>" method="post">としています。次の項でupdateアクションを追加します。

  • updateアクションの追加

Userコントローラーにupdateアクションを追加します。updateアクションはDBにユーザー情報を上書きするだけなのでviewファイルを新たに作る必要はありません。

class UsersController < ApplicationController
  def index
     @users = User.all
  end

  def new
    @user = User.new
  end

  def home
  end

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

  def create
    @user = User.new(user_params)

    if @user.save
      redirect_to '/users/index'
    else
      render '/users/new'
    end
  end

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

    if @user.update
      redirect_to '/users/index'
    else
      render '/users/edit'
    end
  end

  private
    def user_params
      params.require(:user).permit(:name, :password, :password_cofirmation)
    end
end

createアクションと似ています。新しくUserオブジェクトを作るのではなくidでDBから検索し、paramsの値を引数にupdateメソッドでDBに保存します。この時Rails serverのログを見るとSQLのクエリが登録時と編集時で異なることがわかります。

登録時(INSERTでDBに保存している)

INSERT INTO "users" ("name", "password_digest", "created_at", "updated_at") VALUES (?, ?, ?, ?)  
[["name", "test"], ["password_digest", "$2a...KG"], ["created_at", "2020-09-29 06:16:15.541364"], ["updated_at", "2020-09-29 06:16:15.541364"]]

編集時(UPDATEでDBに保存している)

UPDATE "users" SET "name" = ?, "password_digest" = ?, "updated_at" = ? WHERE "users"."id" = ?  
[["name", "change3"], ["password_digest", "$2...li"], ["updated_at", "2020-09-29 06:16:29.407794"], ["id", 3]]

以上で編集機能が追加できました。

ユーザー削除機能の追加

削除をする時の流れは以下の通りです。

① ユーザー一覧の削除したいユーザーの削除ボタンを押す。

ルーターによりdestroyアクションが実行され、確認メッセージをブラウザに表示した後ユーザーが削除される。

③ 削除完了後、ユーザー一覧にリダイレクトされる。

  • ルーティングの設定

次のようにルーティングを設定します。

Rails.application.routes.draw do
  get 'users/index'
  get 'users/new'
  get 'users/home'
  get '/users/create', to: 'users#new'
  post '/users/create'
  get '/user/:id/edit', to: 'users#edit', as: 'edit_users'
  patch '/users/:id', to: 'users#update'
  delete '/users/:id', to: 'users#destroy', as 'destroy_users'

  root 'users#index'
end
  • viewの編集

ユーザー一覧に削除ボタンを追加します。

<h1>ユーザー一覧</h1>
<%= link_to '登録画面へ', '/users/new' %>
<table>
  <tr>
    <th>ユーザー名</th>
  </tr>

  <% @users.each do |user| %>
  <tr>
    <td><%= user.name %></td>
    <td><%= link_to 'Edit', edit_users_path(user) %></td>
    <td><%= link_to 'Destroy', destroy_users_path(user), method: :delete, data: { confirm: 'Are you sure' } %></td>
  </tr>
  <% end %>
</table>
  • destroyアクションの追加

Userコントローラーにdestroyアクションを追加します。

class UsersController < ApplicationController
  def index
     @users = User.all
  end

  def new
    @user = User.new
  end

  def home
  end

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

  def create
    @user = User.new(user_params)

    if @user.save
      redirect_to '/users/index'
    else
      render '/users/new'
    end
  end

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

    if @user.update
      redirect_to '/users/index'
    else
      render '/users/edit'
    end
  end

  def destroy
    @user = User.find(params[:id])
    @user.destroy
 
    redirect_to users_index_path
  end

  private
    def user_params
      params.require(:user).permit(:name, :password, :password_cofirmation)
    end
end

これでユーザーが削除できるようになりました。削除時のSQLは次のようになっていることがRails severのログから確認できます。

User Destroy (0.9ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 3]]

まとめ

今回でユーザーの編集・削除機能が完成しました。

ログイン機能を満たす為には認証機能を用いて編集や削除できる範囲を自分のユーザーのみにする必要があります。

続きとして認証機能を追加していきたいと思います。

参考文献

Ruby on Rails ガイド

Ruby on Rails チュートリアル

Railsのシンプルなログイン機能 Part2

目次

はじめに

 ログイン機能の勉強として機能を細分化しつつ実装します。

 理解するための実装なので設計上好ましくない実装が含まれます。できるだけシンプルに実装し、理解し易さを求めたので今回のような実装になりました。ないとは思いますが、後述するコードを参考にする際はお気をつけください。

  • 環境
バージョン
OS OS X 10.15.6
ruby 2.6.4
rails 6.0.3

 前回の続きをやっていきます。前回はユーザー情報をデータベースに登録する機能を実装しました。それに次の項目を加えます。

  1. パスワードを保存する際の暗号化
  2. 登録情報のバリデーション
  3. エラー処理

設計

  • データベース

 あとで実装するパスワードの暗号化のためにパスワードのカラム名をpassword_digestというカラムに変更します。

カラム 用途 データ型
id 自動生成のID intger
name ユーザーネーム string
password_digest パスワード string
  • 機能(追加)

    1. パスワードを暗号化してデータベースに保存する

    2. 登録情報(ユーザーネーム、パスワード)の登録制限機能(バリデーション)

    3. 項目2で設定した入力制限により登録ができない時の処理(エラー処理)

  • ビュー

ファイル名 内容
index.html.erb ユーザー一覧
new.html.erb 登録画面

実装

パスワードを暗号化してデータベースに保存する

パスワードの暗号化機能に必要なことは大きく分けると以下の通りです。

・has_secure_passwordメソッドを使う

・パスワードはDBのpassword_digestカラムに保存する

・ bcrypt gemの追加

  • データベースの変更

パスワードを保存するカラム名をpassword_digestに変更します。

次のコマンドでマイグレーションファイルを作成します。

$ rails g migration rename_password_password_digest_column_to_Users

作成したマイグレーションファイルを次のように変更します。

class RenamePasswordPasswordDigestColumnToUsers < ActiveRecord::Migration[6.0]
  def change
        rename_column :users, :password, :password_digest
  end
end

最後にdb:migtateを実行しDBに反映させます。

$ rails db:migrate

Userモデルを確認すると、annotateによるスキーマ情報が変更されているのがわかります(実際にDBも変更されています)。

# == Schema Information
#
# Table name: users
#
#  id              :integer          not null, primary key
#  name            :string
#  password_digest :string
#  created_at      :datetime         not null
#  updated_at      :datetime         not null
#
class User < ApplicationRecord
end
  • Userコントローラーの編集

has_secure_passwordではpassword属性とpassword_confirmation属性のものがフォームから送られてきた時、その2つが同じ値ならばパスワードを暗号化してDBのpassword_digestカラムに暗号化されたパスワードを保存します。そのため、strong parametersに:password_cofirmationを追加します。

class UsersController < ApplicationController
  def index
     @users = User.all
  end

  def new
  end

  def home
  end

  def create
    @user = User.new(user_params)

    @user.save
    redirect_to '/users/index'
  end

  private
    def user_params
      params.require(:user).permit(:name, :password, :password_cofirmation)
    end
end
  • viewファイルの編集

Userコントローラーと同様にpassword_cofirmation属性のinputタグを追加します。

<h1>ユーザー登録</h1>
<%= link_to 'ユーザー一覧', '/users/index' %>
<form action="/users/create" method="post">
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
  <ul>
    <li>
      <label for="user_name">Name:</label>
      <input type="text" id="user_name" name="user[name]">
    </li>
    <li>
      <label for="user_password">Password:</label>
      <input type="password" id="user_password" name="user[password]">
    </li>
    <li>
      <label for="user_password">Password(confirm):</label> 
 
     <input type="password" id="user_password_confirmation" name="user[password_confirmation]">
    </li>
    <li>
      <input type="submit" value="登録">
    </li>
  </ul>
</form>
  • bcryptの追加

Gemfileにbcryptを追加してbundle installを実行します。

bcryptはデフォルトでコメントアウトされている場合があるのでコメントアウト されていたらコメントアウトを解除し、なければ追加します。

...
gem 'bcrypt',     '3.1.7'
...
$ bundle install
  • has_secure_passwordの追加

userモデルにhas_secure_passwordを追加します。

# == Schema Information
...
class User < ApplicationRecord
  has_secure_password
end

以上で、パスワードの暗号化が実装されました。暗号化する前と後のデータベースの中身は次の通りです。

SQLite version 3.28.0 2019-04-15 14:49:49
Enter ".help" for usage hints.
sqlite> SELECT "users".* FROM "users";
...
8|foo|bar|2020-09-28 06:06:23.205372|2020-09-28 06:06:23.205372
9|hoge|$2a$12$deW7iUy7UnXXUMAYPLur.OHd7G7lhzTbI0AwA95I7XO.QOBZjNe4e|2020-09-28 06:17:23.433464|2020-09-28 06:17:23.433464
sqlite>

一番左のカラムがidであり、idが9のデータを挿入する前に暗号化を追加しました。左から3番目のカラムがpassword_digestのカラムで暗号化されているのがわかります。

登録情報(ユーザーネーム、パスワード)の登録制限機能(バリデーション)

ここでは、名前やパスワードの登録に制限をかけます。具体的には次の通りです。

・名前:50文字以内。空欄禁止。

・パスワード:8文字以上。空欄禁止。

パスワードに関して、8文字以上の制限だけで空欄禁止も含むかと思われますが、文字数制限だけでは6文字分の空白スペースなどに対応できないため空白禁止の制限も追加します。

この制限を実装するにはUserモデルにバリデーション機能を追加します。

  • Usesrモデルの編集

Userモデルに次のようにバリデーションを追加します。

# == Schema Information
...
class User < ApplicationRecord
  has_secure_password

  validates :name, presence: true, length: { maximum: 50 }
  validates :password, presence: true, length: { minimum: 8 }
end

これにより、名前は1文字以上50文字以内(空欄禁止)でパスワードは8文字以上という制限が追加されました。

登録制限は実装できましたが、このままでは登録できなかった時と登録できた時の違いがわかりません。そこで、次の項で登録失敗の時はエラーを表示するようにします。

登録ができない時の処理(エラー処理)

エラー処理の手順は次の通りです。

①Userコントローラーに登録成功時と失敗時の分岐を追加する。

②Userコントローラーのnewメソッドにインスタンス変数を追加する。

③viewファイルにエラーメッセージの表示を追加

  • Userコントローラーの変更

次のようにUserコントローラーを修正します。

class UsersController < ApplicationController
  def index
     @users = User.all
  end

  def new
    @user = User.new
  end

  def home
  end

  def create
    @user = User.new(user_params)

    if @user.save
      redirect_to '/users/index'
    else
      render '/users/new'
    end
  end

  private
    def user_params
      params.require(:user).permit(:name, :password, :password_cofirmation)
    end
end

newメソッドでは空のインスタンス変数を作成しています。これがないと登録ページにアクセスした時、インスタンス変数@Userがnilになりエラーが出ます。

登録成功時と失敗時の分岐はcreateメソッドのif分で実装しています。@user.saveはDBへの保存は成功した時trueを返し、失敗した時(登録制限に引っ掛かった時)falseを返します。成功時は今まで通りユーザー一覧にリダイレクトし、失敗時は登録ページ(現在の)にリダイレクトしエラーを表示します。

  • viewファイルの変更

viewファイルを次のように修正します。

<h1>ユーザー登録</h1>
<%= link_to 'ユーザー一覧', '/users/index' %>
<form action="/users/create" method="post">
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>

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

  <ul>
    <li>
      <label for="user_name">Name:</label>
      <input type="text" id="user_name" name="user[name]">
    </li>
    <li>
      <label for="user_password">Password:</label>
      <input type="password" id="user_password" name="user[password]">
    </li>
    <li>
      <label for="user_password">Password(confirm):</label>
      <input type="password" id="user_password_confirmation" name="user[password_confirmation]">
    </li>
    <li>
      <input type="submit" value="登録">
    </li>
  </ul>
</form>

登録に失敗した時は@userにエラーのオブジェクトが追加されます。<% if @user.errors.any? %>とすることで、エラーがある時はエラーを表示し、エラーがないときは通常の登録フォームを表示することができます。

全て空欄でフォームを送信すると次のようになります。

f:id:aoshota:20200928170842p:plain
ユーザー登録失敗時のエラーメッセージ(全て空欄)

passwordとpassword_confirmationが違う時は次のようなエラーになります。

f:id:aoshota:20200928171038p:plain
ユーザー登録失敗時のエラーメッセージ(確認用のパスワードが間違っている時)

エラー表示は実装できましたが、今のままだとエラー表示後にブラウザを再読み込みするとRailsのエラーになってしまいます。そこでルーティングを次のように変更します。

Rails.application.routes.draw do
  get 'users/index'
  get 'users/new'
  get '/users/create', to: 'users#new'
  post 'users/create'

  root 'users#index'
end

フォームの送信はPOSTリクエストで送信されるようにHTMLを作成したがブラウザの読み込みはGETリクエストなのでcreateアクションにGETリクエストが来た時のルーティングをnewアクションに設定しています。

まとめ

今回でユーザーの登録機能が完成しました。

次回はユーザーの編集・削除機能の追加となります。

参考文献

Ruby on Rails ガイド

Ruby on Rails チュートリアル

Railsのシンプルなログイン機能 Part1

目次

はじめに

ログイン機能の勉強として機能を細分化しつつ実装します。今回はユーザーをデータベースに登録し、ユーザーの一覧を表示されるところまで。

理解するための実装なので設計上好ましくない実装が含まれます。できるだけシンプルに実装し、理解し易さを求めたので今回のような実装になりました。ないとは思いますが、後述するコードを参考にする際はお気をつけください。

  • 環境
バージョン
OS OS X 10.15.6
ruby 2.6.4
rails 6.0.3

設計

  • データベース
カラム 用途 データ型
id 自動生成のID integer
name ユーザーネーム string
password パスワード string
  • 機能

    1. ユーザー登録

    2. ユーザー一覧表示

    ここでは、ユーザーを登録して、ユーザー一覧を表示するだけです。
    ユーザー削除やユーザー編集、認証機能はここでは実装しません。

  • ビュー

ファイル名 内容
index.html.erb ユーザー一覧
new.html.erb 登録画面

実装

  • 新しいRailsアプリを作成。
$ rails new simple_login

gem annotate を追加。(annotateの追加方法)

  • modelとデータベース作成

下記コマンドでユーザーモデルを作成。

$ rails g model User name:string password:string

下記コマンドでデータベースを作成。

$ rails db:migrate
  • controller作成
$ rails g controller Users index new create
  • ルーティング設定

コントローラーを作成した際に生成されたroutes.rbを次のように書き換える。

Rails.application.routes.draw do
  get 'users/index'
  get 'users/new'
  post 'users/create'

  root 'users#index'
end

Usersコントローラーのcreateメソッドはユーザー登録のメソッドなのでgetからpostに変更する。また、ルートへのパスをユーザー一覧画面であるindexに変更する。

  • viewの編集

① 登録画面( new.html.erb )

基本的にはよくあるHTMLのフォームです。4行目はPOSTリクエストを送るためのRailsのおまじないだと思ってください(CSRF保護を通過するためらしいです)。

<h1>ユーザー登録</h1>
<%= link_to 'ユーザー一覧', '/users/index' %>
<form action="/users/create" method="post">
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
  <ul>
    <li>
      <label for="user_name">Name:</label>
      <input type="text" id="user_name" name="user[name]">
    </li>
    <li>
      <label for="user_password">Password:</label>
      <input type="password" id="user_password" name="user[password]">
    </li>
    <li>
      <input type="submit" value="登録">
    </li>
  </ul>
</form>

② ユーザー一覧 ( index.html.erb )

<h1>ユーザー一覧</h1>
<%= link_to '登録画面へ', '/users/new' %>
<table>
  <tr>
    <th>ユーザー名</th>
  </tr>

  <% @users.each do |user| %>
  <tr>
    <td><%= user.name %></td>
  </tr>
  <% end %>
</table>
  • controllerの編集

① indexメソッド

登録されているユーザーをUser.allで全て取得してindexビューに渡します。

② newメソッド

newビューを表示するだけなので何も記述しません。

③ createメソッド

フォームのページからのparamsをプライベートクラスに渡しuserに関するものだけにします。それを元にUser.new(user_params)でフォームから送られてきたnameとpasswordで新しいオブジェクトを作成します。そのオブジェクトをインスタンス変数@userに代入します。インスタンス変数@userをsaveメソッドでデータベースに保存します。最後にユーザー一覧にリダイレクトします。

class UsersController < ApplicationController
  def index
    @users = User.all
  end

  def new
  end

  def create
    @user = User.new(user_params)

    @user.save
    redirect_to '/users/index'
  end

  private
    def user_params
      params.require(:user).permit(:name, :password)
    end
end
  • 今回の設計要件は以上で満たしました。

まとめ

以上で、ユーザー登録とユーザー一覧表示の機能は実装できました。ただ、これだけ質素な機能でも考慮すべき点がいくつもあります。

  1. 登録情報のバリデーション
  2. パスワードを保存する際の暗号化
  3. ユーザー一覧のページネーション
  4. エラー処理

今の登録情報は名前とパスワードですが認証機能がないので、ただuserテーブルの”name”と”password”というカラムにデータを保存しているだけの状態です。ログイン機能を実装するには次の項目も実装する必要があります。

  1. ユーザー削除
  2. ユーザー編集
  3. 認証機能
  4. リファクタリング(フォームヘルパーやパーシャルの活用)
  5. RESTfullなルーディング

上記の項目を追加してやっと”ただのログイン機能”が実装できます。これに加えてユーザーの投稿やいいね機能などSNSの基本的な機能を追加してやっとアプリケーションらしくなっていきます。いきなりは難しいので徐々に機能追加していきたいと思います。

参考文献

Ruby on Rails ガイド

データベースのスキーマ情報をmodelファイルに追加するgem、annotateの使い方

annotateの使い方

 各モデルのスキーマ情報をファイルの先頭もしくは末尾にコメントとして書き出してくれるgem。
 例えば、app/model/user.rb ファイルの最初にテーブルのカラム等を記述してくれる。

① Gemfileに追加

gem 'annotate'

② gemとdbを更新。

$ bundle install
$ rails g annotate:install
$ rails db:migrate

スキーマ情報が書き出される。

# == Schema Information
#
# Table name: users
#
#  id               :integer          not null, primary key
#  crypted_password :string
#  email            :string           not null
#  salt             :string
#  created_at       :datetime         not null
#  updated_at       :datetime         not null
#
# Indexes
#
#  index_users_on_email  (email) UNIQUE
#
class User < ApplicationRecord
end

参考文献

テスト投稿

目次

はじめに

プログラミングの勉強したことをまとめていきます。

マークダウンテスト

はてなブログのマークダウン記法の確認です。

Hello Worldをいくつかの言語で書いてみます。

1. C言語

#include <stdio.h>

int main(void)
{
    printf("Hello World\n");

    return (0);
}

2. C++

#include <iostream>
using namespace std;

int main()
{
    cout << "Hello World" << endl;

    return(0);
}

3. Ruby

puts "Hello World"

4. Python

print("Hello World")

5. PHP

<?php
    echo "Hello World\n"
?>

感想

目次を作るのが楽なような制約があるような。
タブ入力はできないのかな?

最近はマークダウン記法を試しているけどプラットフォームによる違いが若干あるのがややこしい。

これからはRailsの勉強したことをまとめていきたい。