前 基礎Ruby on Rails Chapter6 レコードの作成、更新、削除
次 基礎Ruby on Rails Chapter8 単数リソース
バリデーション
バリデーションとエラー情報
- saveメソッドを呼び出すと、バリデーションを実行する。
- Memberモデルに、validatesメソッドを加えてみる。
class Member < ApplicationRecord
validates :number, presence: true
- member.number=nilにして、保存してみると、saveメソッドがfalseを返している。
-
member.errors.messages
で、エラーの中身が見ることができる。{:number=>["can't be blank"]}
-
member.errors.empty?
で、エラーオブジェクトの有無が確認できる。 -
member.errors[:number]
で、属性ごとのエラー情報を取り出すことができる。 -
member.valid?
は、エラーなし?という意味で、エラーがある場合、falseを返す。 -
member.invalid?
は、エラーあり?という意味で、エラーがある場合、trueを返す。
irb(main):001:0> member = Member.first
Member Load (0.4ms) SELECT "members".* FROM "members" ORDER BY "members"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Member id: 1, number: 10, name: "Taro", full_name: "佐藤 太郎", email: "Taro@example.com", birthday: "1981-12-01", sex: 1, administrator: true, created_at: "2018-09-21 14:01:43", updated_at: "2018-09-21 14:01:43">
irb(main):002:0> member.number = nil
=> nil
irb(main):003:0> member.save
(0.0ms) begin transaction
(0.1ms) rollback transaction
=> false
irb(main):004:0> member.errors.messages
=> {:number=>["can't be blank"]}
irb(main):005:0> member.errors.empty?
=> false
irb(main):006:0> member.errors[:number]
=> ["can't be blank"]
irb(main):007:0>
validatesメソッドの書き方
- validatesメソッドの引数には、シンボルでモデルの属性名を指定し、ハッシュでバリデーションの種類:trueを並べる。属性名、バリデーションともに複数並べられる。
- バリデーションの種類:{オプション:オプションの値}とすると、バリデーションごとにオプションを指定できる。
validates :number, :name, presence: true
validates :name, length: { maximum: 20 }
会員情報の検証
app/models/member.rb(一部)
class Member < ApplicationRecord
# numberのバリデート。nil,空,全角/半角空白禁止
validates :number, presence: true,
numericality: {
# 整数のみ
only_integer: true,
# 0以上
greater_than: 0,
# 100未満
less_than: 100,
# presenceとの重複を避けるため
allow_blank: true
},
# 重複禁止
uniqueness: true
# nameのバリデート。nil,空,全角/半角空白禁止
validates :name, presence: true,
# アルファベットから始まり、英数字のみ
format: { with: /\A[A-Za-z][A-Za-z0-9]*\z/, allow_blank: true },
# 2文字以上20文字以下
length: { minimum: 2, maximum: 20, allow_blank: true },
# 重複禁止
uniqueness: { case_sensitive: false }
# full_nameのバリデート。nil,空,全角/半角空白禁止。20文字以下
validates :full_name, presence: true, length: { maximum: 20 }
メールアドレスのチェック
- メールアドレスのチェックは複雑なので、既存のGemパッケージを利用する。
Gemfile
gem 'email_validator', '~> 1.6'
- ctrl-cでRailsサーバを止めて、bundle installコマンドを実行する。サーバを起動しなおす。
$ bundle install
$ bin/rails s
app/models/member.rb(一部)
# emailのバリデート
validates :email, email: { allow_blank: true }
エラーメッセージの表示
- エラー表示のテンプレートを作成する。
- full_messagesは、エラーを出した属性+メッセージの配列を返す。
app/views/shared/_errors.html.erb
<% if obj.errors.present? %>
<div id="errors">
<h3>エラーがあります。</h3>
<ul>
<% obj.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
- 上記の部分テンプレートを表示する部分を、先頭に追加する。
-
obj: @member
で、_errors.html.erbのローカル変数objがモデルオブジェクトを参照するようにする。
app/views/members/_form.html.erb(一部)
<%= render "shared/errors", obj: @member %>
- エラー表示用のCSSファイルを追加する。
- エラーを起こした入力欄は、class属性が
field_with_errors
のdivタグで囲まれる。
app/assets/stylesheets:errors.css
/* エラー表示 */
div#errors {
background-color: #fee;
border: 1px solid #ecc;
padding: 15px;
margin: 0 0 1em;
}
div#errors h2 {
font-size: 90%;
color: red;
margin: 0 0 4px;
border: none;
}
div#errors ul {
margin: 0;
padding-left: 1.5em;
}
div.field_with_errors {
background-color: #fcc;
padding: 2px;
}
Railsの国際化機能
- Railsの国際化機能は、I18nというクラスにロケールを設定し、ロケールに合わせてYAML形式のロケールテキストから文字列を読み込んで表示する。
- ロケールを設定するには、コントローラでロケールを表す文字列やシンボルを設定する。
I18n.locale = "ja"
- 指定がなければデフォルトのロケール「en」が使われる。
- application.rbにデフォルトのロケールを設定する。
config/application.rb
config.i18n.default_locale = :ja
エラーメッセージの日本語化
Gemパッケージrails-l18n
- Gemパッケージ「rails-i18n」は、さまざまな言語のためのエラーメッセージや日付の書式などを集めたもの。
- Gemfileに追加する。
Gemfile
gem 'rails-i18n', '~> 5.1'
- ターミナルでrails-i18nをインストールする。
$ bundle install
モデルの属性名の日本語化
- 日本語テキストを記述する、ja.ymlを作成する。
config/locales/ja.yml
ja:
activerecord:
models:
member: 会員情報
attributes:
member:
number: 背番号
name: ユーザー名
full_name: 氏名
sex: 性別
sex_1: 男
sex_2: 女
birthday: 誕生日
email: メールアドレス
administrator: 管理者
- _form.html.erbの
form.label :number, "背番号"
のように、日本語がある部分を取る。ja.ymlを利用する。 - human_attribute_nameは、モデルの属性名をロケールテキストから取り出す。
app/views/members/_form.html.erb
<%= render "shared/errors", obj: @member %>
<table class="attr">
<tr>
<th><%= form.label :number %></th>
<td><%= form.text_field :number, size: 8 %></td>
</tr>
<tr>
<th><%= form.label :name %></th>
<td><%= form.text_field :name %></td>
</tr>
<tr>
<th><%= form.label :full_name %></th>
<td><%= form.text_field :full_name %></td>
</tr>
<tr>
<th>性別</th>
<td>
<%= form.radio_button :sex, 1 %>
<%= form.label :sex_1 %>
<%= form.radio_button :sex, 2 %>
<%= form.label :sex_2 %>
</td>
</tr>
<tr>
<th>
<%= form.label :birthday, for: "member_birthday_li" %>
</th>
<td>
<%= form.date_select :birthday, start_year: 1940, end_year: Time.current.year, use_month_numbers: true %>
</td>
</tr>
<tr>
<th><%= form.label :email %></th>
<td><%= form.text_field :email %></td>
</tr>
<tr>
<th><%= Member.human_attribute_name(:administrator) %></th>
<td>
<%= form.check_box :administrator %>
<%= form.label :administrator %>
</td>
</tr>
</table>
- 日本語になったことを確認する。
エラーメッセージのカスタマイズ
- 「は不正な値です。」のテキストを変えたければ、ja:→activerecord→errors→messagesの下に、「エラー名:文字列」を記述する。
config/locale/ja.yml(一部)
ja:
activerecord:
(略)
errors:
messages:
invalid: "の書式が正しくありません。"
- 新しいエラーメッセージを追加するには、
invalid_member_name
のように、新たな文字列で作成する。
config/locale/ja.yml(一部)
ja:
activerecord:
(略)
errors:
messages:
invalid_member_name: "は半角英数字で入力してください。"
- 上記で追加したエラーメッセージ
:invalid_member_name
を追加する。
app/models/member.rb(一部)
# nameのバリデート。nil,空,全角/半角空白禁止
validates :name, presence: true,
# アルファベットから始まり、英数字のみ
format: { with: /\A[A-Za-z][A-Za-z0-9]*\z/, allow_blank: true, message: :invalid_member_name },
YAML
- yamlファイルの読み込み方法
require "yaml"
animals = YAML.load(File.new("members.yml"))
members.each do |key, val|
puts "#{val['number']}\t#{val['name']}"
end
国際化機能の使い方
テキスト
- 日本語用のテキストを用意する
ja:
messages:
hello: "こんにちは"
- ロケールの設定の文字列を取り出す。
s = I18n.t("messages.hello")
- コントローラやテンプレートの中では、I18nを付けずに、tメソッドが使える。
<%= t("messages.hello") %>
- テキストの中に値を埋め込む。
ja:
messages:
hello: "%{name}こんにちは"
- 引数に、ハッシュを追加すれば、「Taroさんこんにちは」というテキストになる。
<%= t("messages.hello", name: "Taro") %>
日付と時刻
- lメソッドの引数には、DateクラスやTimeクラス、ActiveSupport::TimeWithZoneクラスのオブジェクトを渡す。
s = I18n.l(Time.current)
- コントローラやテンプレートの中では、I18nを付けずに、lメソッドが使える。
<%= l(Time.current) %>
- lメソッドの第2引数には、formatオプションを指定できる。
- :longは「2018年05月05日(土) 17時06分56秒 +0900」のような文字列になる。
<%= l(Time.current, format: :long) %>
- 自分で日付フォーマット作成したい場合、以下のように書式を登録する。
condig/locales/ja.yml(一部)
ja:
time:
(略)
formats:
default:
medium: "%Y年%m月%d日(%a) %H:%M"
- formatオプションで指定すれば、上記フォーマットのようになる。
<%= l(Time.current, format: :medium) %>