メッセージプレビューあるある
メッセージ機能で実際にあったお話。
メッセージを送るのに、以下のように preview
で内容のバリデーションをしつつ見た目の確認をし、create
で保存、かつ、通知メールを出す、という処理があったとする。
(実際のコードは書けないので、かなり適当にサンプルコードは書いてる。。。)
class MessagesController < ApplicationController
def new
# 略
end
# メッセージのプレビュー
def preview
@message = Message.new
@message.attributes = message_params
return if @message.valid?
render :new
end
# メッセージ作成
def create
@message = Message.new
@message.attributes = message_params
Message.transaction do
@message.save!
UserMailer.message_notification(@message.receiver)
end
end
private
def message_params
# 略
end
end
※実際の処理には、Message モデルの validation で利用可能文字の制限や文字列の長さ制限をしている。
普通の使い方をしていれば、preview
-> create
の間に validation エラーになるようなものは発生しない…はずだが…問題が起こることがある。
実際に下記のことが発生していた。
文字コードの誤判定
おそらくブラウザの文字コード誤判定か何かだと思うのだけど、UTF-8で書かれるべき文字列がSJISと思われる化けた文字で送信されていた。
※「と思われる」というのは再現できたけど、ユーザがそうしたかどうかわからないから。ログには化けた文字が送信されていることが記録されていた。
↑の理由により、利用可能文字制限にひっかかってsave!
による例外発生で、システムエラーになっていた。
ブラウザの文字コード変換機能を利用するとたしかに再現できた。(見た目も化けるから普通おかしいと思って送信しないとは思うけど…)ので、preview
しているとはいえ、validation にひっかかる値が混入する可能性がある。
対応
とりあえず、create
のときも、validation でエラーになることを想定し、エラーの場合は編集画面に飛ばすということをしています。
class MessagesController < ApplicationController
# 略
# メッセージ作成
def create
@message = Message.new
@message.attributes = message_params
begin
Message.transaction do
@message.save!
@message.sent_notification(@message.receiver)
end
# ここで save! で例外が発生したときは編集画面に戻す
rescue ActiveRecord::RecordInvalid
render :new
return
end
end
# 略
end
まとめ
preview
で安心せずに、create
でもバリデーションエラーに備える。