Techioz Blog

Ruby on Rails - モデルの検証を考案する

概要

私は Ruby on Rails アプリケーションに取り組んでおり、認証に Devise gem を使用しています。新しいユーザーとしてサインアップすることはできますが、ユーザーのすべてのデータが Devise User モデルに保存されていないことに注意しました。

以下のシナリオについて説明しました。

ActiveRecord::Schema[7.0].define(version: 2023_08_07_053734) do
  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "company_departments", force: :cascade do |t|
    t.integer "department_code"
    t.string "department_name"
    t.string "department_haed"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.string "user_name"
    t.integer "user_identification_number"
    t.date "user_employment_start_date"
    t.date "user_DOB"
    t.string "user_present__job_title"
    t.string "user_department"
    t.string "user_employment_category"
    t.string "user_office_working_preference"
    t.string "user_social_status"
    t.string "user_present_office_location"
    t.string "user_present_working_shift"
    t.bigint "user_basic_pay"
    t.bigint "user_gross_salary"
    t.integer "user_appraisal_rating"
    t.date "user_last_salary_revision_date"
    t.text "user_appraisal_comments"
    t.bigint "user_contact"
    t.string "user_personalemail"
    t.text "user_permanent_address"
    t.string "user_manager"
    t.string "user_sup1"
    t.string "user_sup2"
    t.string "user_sup3"
    t.string "user_sup4"
    t.text "user_permanent_illness"
    t.string "user_phstatus"
    t.string "user_companyname"
    t.string "user_skill_category"
    t.boolean "user_account_status"
    t.datetime "remember_created_at"
    t.integer "sign_in_count", default: 0, null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string "current_sign_in_ip"
    t.string "last_sign_in_ip"
    t.string "confirmation_token"
    t.datetime "confirmed_at"
    t.datetime "confirmation_sent_at"
    t.string "unconfirmed_email"
    t.integer "failed_attempts", default: 0, null: false
    t.string "unlock_token"
    t.datetime "locked_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.bigint "company_department_id"
    t.index ["company_department_id"], name: "index_users_on_company_department_id"
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

  add_foreign_key "users", "company_departments"
end

会社部門モデル:

class CompanyDepartment < ApplicationRecord
 has_many :users
end

ユーザーモデル:

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable


  belongs_to :company_department, optional: true
end

私は何をしようとしているのでしょうか?

Company Division テーブルのレコードを、Devise サインアップ フォームの [Department] フィールドのドロップダウン オプションのリストとして利用できるようにしたいと考えています。

観察:

サインアップ フォームは機能していますが、会社部門のデータが User テーブルに保存されていないことがわかりました。

ただし、Rails コンソールに移行し、以下のクエリを使用してバックエンドから変更を加えようとすると、部門データは以下のように User テーブルに正常に保存されます。

User.create!(user_name: "abc", password: 123456, password_confirmation: 123456, company_department_id: 3

思考プロセス

これは検証に関連するものだと思います。したがって、以下のようにすべてのユーザー モデル属性をホワイトリストに登録したことを確認しました。

アプリケーションコントローラー:

class ApplicationController < ActionController::Base
    include DeviseWhitelist
end

ホワイトリストへの懸念を工夫する

module DeviseWhitelist 
  extend ActiveSupport::Concern

  included do 
    before_action :configure_permitted_parameters, if: :devise_controller?
  end 

  def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:user_name, :user_identification_number, :user_employment_start_date, :user_DOB, :user_present__job_title, :user_department, :user_employment_category, :user_office_working_preference, :user_social_status, :user_present_office_location, :user_present_working_shift, :user_basic_pay, :user_gross_pay, :user_appraisal_rating, :user_last_salary_revision_date, :user_appraisal_comments, :user_contact, :user_personalemail, :user_permanent_address, :user_manager, :user_sup1, :user_sup2, :user_sup3, :user_sup4, :user_permanent_illness, :user_phstatus, :user_companyname, :user_skill_category, :user_account_status, **:company_department_id**])

    devise_parameter_sanitizer.permit(:account_update, keys: [:user_name, :user_identification_number, :user_employment_start_date, :user_DOB, :user_present__job_title, :user_department, :user_employment_category, :user_office_working_preference, :user_social_status, :user_present_office_location, :user_present_working_shift, :user_basic_pay, :user_gross_pay, :user_appraisal_rating, :user_last_salary_revision_date, :user_appraisal_comments, :user_contact, :user_personalemail, :user_permanent_address, :user_manager, :user_sup1, :user_sup2, :user_sup3, :user_sup4, :user_permanent_illness, :user_phstatus, :user_companyname, :user_skill_category, :user_account_status, **:company_department_id**])
  end 

end 

以下は私がサインアップに使用しているフォームです。デフォルトでは、部門の追加選択フィールドを備えた新しい登録フォームを考案します。

新規ユーザー/サインアップフォームを工夫する

<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="field">
    <%= f.label :password %>
    <% if @minimum_password_length %>
    <em>(<%= @minimum_password_length %> characters minimum)</em>
    <% end %><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :user_department %><br />
   <%= f.collection_select(:user_department, CompanyDepartment.all, :id, :department_name) %>
  </div>

  <div class="actions">
    <%= f.submit "Sign up" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>

部門データが保存されない理由が理解できず、これに関してサポートを求めたいと考えました。ありがとう。

以下では、POST リクエストが開始されると、パラメーターは正しくキャプチャされますが、部門の詳細は保存されないことがわかります。

解決策

company_Department_id を更新しようとしているので、次のようにします。

f.collection_select(:company_department_id ...

2 つの異なる属性を丸で囲みました。コンソールでは正しい属性を使用していますが、フォーム内の別の属性である user_Department は実際には更新されます。