Form Objectとは
Formで使うためのモデルみたいなやつ。
Railsのフォームは基本的にActiveRecordのモデルに依存している。
1つのフォームで複数モデルの操作をしたいときにForm Objectを使うと、処理がすっきりかける。
またログインに関する処理など、既存のモデルが使えない処理もForm Objectに書くと良い場合がある。
あんまり使わない方が良いって意見もある。
ログイン機能にform_objectを使う場合のサンプル
Railsチュートリアルとかで解説されてる、bcrypt
等を使ったログイン機能にForm Objectをいれることを想定。
form_object
$ mkdir app/forms
$ touch app/forms/login.rb
app/forms/login.rb
class Login
include ActiveModel::Model
attr_accessor :email, :password #使うカラム
validates :email, presence: true
validates :password, presence: true
def save
return false if invalid?
true
end
end
controller
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
@login = Login.new
end
def create
@login = Login.new(login_params)
if @login.save && (@user = User.find_by(email: @login.email)) && @user.authenticate(@login.password)
login @user
redirect_to users_path
else
render :new
end
end
private
def login_params
params.require(:login).permit(%i[email password])
end
end
view
app/views/sessions/new.html.erb
<%= form_with model: @login, url: login_path, local: true do |f| %>
<%= f.text_field :email %>
<%= f.password_field :password %>
<%= f.submit "ログイン" %>
<% end %>
locale
$ touch config/locales/models/login.ja.yml
config/locales/models/login.ja.yml
ja:
activemodel:
attributes:
login:
email: メールアドレス
password: パスワード
カスタムバリデーションを追加
app/forms/login.rb
class Login
include ActiveModel::Model
attr_accessor :email, :password
validates :email, presence: true
validates :password, presence: true
validate :valid_combination
# ユーザーが見つからない、またはパスワードに誤りがある場合にエラーを返す
def valid_combination
@user = User.find_by(email: email)
errors.add(:base, 'メールアドレスとパスワードの組み合わせが正しくありません。') unless @user&.authenticate(password)
end
def save
return false if invalid?
true
end
end