はじめに
半年以上前に作成したWebアプリケーションのModel等を見返し、当時の設計の意図や、今になって気づいた改善点を整理します。
作成したUserModel
class User < ApplicationRecord
has_many :clothings, dependent: :destroy
has_secure_password
validates :name, presence: true
validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :password, presence: true, length: { minimum: 6 }, on: :create
end
各メソッド解説
has_many :clothing
has_manyは、テーブル同士を関連付けの定義です
服を管理することを目的としたアプリなのでユーザーは複数の服を所有する設計です
dependent: :destroy
親モデル(User)が削除されたら場合に、それに紐づいた子モデル(Clothing)の情報も削除される設計です
has_secure_password
bcrypt(Gem)を追加すると使えるようになる、パスワードをハッシュ化して保存するメソッドです
パスワードは平文で保存してはいけない為必須です
validates
データを保存する際の制約
emailカラムで例えると、空ではないこと、一意性があること、入力形式がメールアドレスかの正規表現を確認しています
改善点
validates :password, presence: true, length: { minimum: 6 }, on: :create
実装当時は on: :create を指定し、新規登録時のみバリデーションを行っていました
これは、ユーザー情報の更新時に、パスワードの再入力を強制しないための記述でした
しかし、このままでは既存ユーザーがパスワードを変更する場合に、6文字未満の短いパスワードを設定できてしまう可能性があります
なので、allow_nilを使用し、update時はパスワードが入力された場合に限りバリデーションをかけるようにするべきだと考えました
[おまけ] scope model内関数の定義
別のモデルで定義していたscopeを解説します
scope :filter_by_category, ->(category_id) { where(category_id: category_id) if category_id.present? }
filter_by_categoryの名の通り、服のカテゴリーでフィルターをかけることを目的としたscopeです
scopeとは、よく使用するクエリをメソッドとして定義する機能です
if category_id.present?を内包し、nilの場合は実行しない設計としています
まとめ
半年以上前のコードを見返すことで、改善点や復習になりました
バリデーションの精度や更新時の挙動を考慮、scopeの安全性など多角的な視点から見て、実装が必要だと実感しました
そのためには1人ではなくチームで開発することの憧れも強く抱きました
機能実装だけで満足せず、セキュリティや保守性の観点から継続的にコードをブラッシュアップしていけるようになりたいです。