Rails: データベースに保存しないチェックボックス値のバリデーション

外観

目的
画面のチェックボックスがオンになっているかどうかを検証します。
チェックボックスの値はデータベースに保存しません。

Active Record バリデーション > 2.1 acceptance

これはWebアプリケーション特有のバリデーションであり、データベースに保存する必要はありません。これに対応するフィールドがなくても、単にヘルパーが仮想の属性を作成してくれます。

環境
Ruby 2.7.2
Rails 6.1.3.2

基礎

メールアドレスを持つAccountモデルを作成します。
新規作成画面に利用規約のチェックボックスを表示します。
メールアドレスと利用規約は必須入力にします。

画像2

rails new howto_validates_acceptance \
--skip-action-mailbox \
--skip-action-text \
--skip-active-storage \
--skip-action-cable \
--skip-javascript \
--skip-turbolinks \
--skip-jbuilder \
--skip-test \
&& cd howto_validates_acceptance && tmux

bin/rails g scaffold Account email
bin/rails db:migrate

# app/models/account.rb
class Account < ApplicationRecord
  validates :email, presence: true
  validates :terms_of_service, acceptance: true, on: :create
end
<!-- app/views/accounts/_form.html.erb -->
  <% if account.new_record? %>
    <div class="field">
      <%= form.label :terms_of_service %>
      <%= form.check_box :terms_of_service %>
    </div>
  <% end %>
# app/controllers/accounts_controller.rb
    def account_params
      params.require(:account).permit(:email, :terms_of_service)
    end

応用

チェックボックスのデフォルト値にtrueを設定する。
チェックボックスの値の引き継ぐ。
チェックボックスとラベルを一列で表示する。

画像1

チェックボックスのデフォルト値にtrueを設定する。

<!-- app/views/accounts/_form.html.erb -->
      <%= form.check_box :terms_of_service, { checked: true } %>

チェックボックスの値の引き継ぐ。
入力エラーとなった場合、前回の入力値を画面に表示する。

<!-- app/views/accounts/_form.html.erb -->
      <%= form.check_box :terms_of_service, { checked: @terms_of_service } %>
# app/controllers/accounts_controller.rb
  def new
    @account = Account.new
    @terms_of_service = false
  end

  def create
    @account = Account.new(account_params)

    if @account.save
      redirect_to @account, notice: 'Account was successfully created.'
    else
      @terms_of_service = param_terms_of_service?
      render :new
    end
  end

    def param_terms_of_service?
      ActiveRecord::Type::Boolean.new.cast(account_params[:terms_of_service])
    end

チェックボックスとラベルを一列で表示する。
スキャフォールドのレイアウトはラベルの下にチェックボックスが表示されます。
これをチェックボックスの右にラベルを表示するように変更します。

<!-- app/views/accounts/_form.html.erb -->
  <% if account.new_record? %>
    <div class="field">
      <%= form.label :terms_of_service do %>
        <%= form.check_box :terms_of_service, { checked: @terms_of_service } %>
        Terms of service.
      <% end %>
    </div>
  <% end %>
// app/assets/stylesheets/scaffolds.scss
.field_with_errors > label > .field_with_errors {
  display: inline; }

今回はconfig.action_view.field_error_procを用いずCSSを修正しました。また、どうせならCSSのhas疑似クラスでチェックボックスを子に持つ要素として指定したかったのですが、現時点でどのブラウザも未対応でした。

以上です。

この記事が気に入ったらサポートをしてみませんか?