二度忘れた事を三度忘れないようにする

しがないフリーランスIT系エンジニア

CarrierWaveを利用したModelの挙動について

幅を広げるのにRoRを勉強し直すのに簡単なアプリを作ってみたらはまったので、メモ。

・とりあえず
プロフィール的なページを構成するのに、メインとなるプロフィールテーブルとhas_oneで2つ別テーブルを関連づけしてました。画像は特定のディレクトリに保存する形をとって、ファイル名をプロフィールテーブルに保存をしようとした。

・そのまえに
RoRのhas_oneで更新をかけると、子テーブルのほうに続々と不要レコードがたまってきたので更新のタイミングで直前のレコードを削除するように、プロフィールモデルをいじってました。

ざっくり)after_initialize時に子テーブルのidを取得→after_commit時に削除

ネットで調べるとhas_manyであれば別の方法があるっぽいけど、うまく動作しなかったのでこうしました。

参考:
has_many側の不要なやつはdeleteして更新したい - Oh! My! Enter! 〜バッチを起動しようと勢いよくキーを叩いたら、それはシフトキーだった〜


・本題
プロフィール編集フォームにて、画像以外の項目で編集しても問題なかったのに画像をアップロードしようとするとエラーが出た。原因は上記のinitialize時のid取得でエラーが出ていたが、画像の有無で挙動が変わっていた。

・結果?
とりあえず「mount_uploader :image, ImageUploader」としたカラムを更新する時は再度initializeが発生する。(おそらく新しくインスタンスを生成しているのではと思う

なお、SQLの実行内容をみていると次のようになっていた。

# 画像無し
Started PATCH "/my_page" for 127.0.0.1 at 2016-08-22 02:48:31 +0000
Processing by UserProfilesController#update as HTML
  Parameters: {"utf8"=>"", -略- "commit"=>"Update User profile"}
  UserProfile Load (0.2ms)  SELECT  -略- LIMIT 1
# ここらへんでafter_initialize動作しているっぽい
  UseService Load (0.2ms)  SELECT  -略- LIMIT 1 # has_oneその1
  UseLang Load (0.3ms)  SELECT  -略- LIMIT 1  # has_oneその2
# ここらへんでafter_initializeが終わっているぽい
BEGIN
  SQL (0.3ms)  has_oneその1をアップデート(ここで古い情報がゴミレコードになる
  SQL (0.2ms)  has_oneその2をアップデート(ここで古い情報がゴミレコードになる
  UserProfile Exists (0.2ms)  親テーブルの重複チェック?
  UserProfile Exists (0.2ms)  親テーブルの重複チェック?
  SQL (0.2ms)  UPDATE 親テーブルのUserProfileで画像以外のカラムを編集
  SQL (0.2ms)  INSERT has_oneその1に更新情報を格納
  SQL (0.2ms)  INSERT has_oneその2に更新情報を格納
COMMIT
# after_commitが動作
  UseService Load (0.2ms)  SELECT  has_oneその1の古い情報を取得
BEGIN
  SQL (0.3ms)  DELETE has_oneその1の古い情報を削除
COMMIT
  UseLang Load (0.2ms)  SELECT  has_oneその2の古い情報を取得
BEGIN
  SQL (0.3ms)  DELETE has_oneその2の古い情報を削除
COMMIT
# after_commitが終了
Redirected to http://++++
Completed 302 Found in 29ms (ActiveRecord: 9.8ms)
# 画像有り
Started PATCH "/profile" for 127.0.0.1 at 2016-08-22 02:49:29 +0000
Processing by UserProfilesController#update as HTML
  Parameters: {"utf8"=>"", -略- "commit"=>"Update User profile"}
  UserProfile Load (0.2ms)  SELECT  -略- LIMIT 1
# ここらへんでafter_initialize動作しているっぽい
  UseService Load (0.2ms)  SELECT  -略- LIMIT 1 # has_oneその1
  UseLang Load (0.3ms)  SELECT  -略- LIMIT 1  # has_oneその2
# ここらへんでafter_initializeが終わっているぽい
BEGIN
  SQL (0.3ms)  has_oneその1をアップデート(ここで古い情報がゴミレコードになる
  SQL (0.2ms)  has_oneその2をアップデート(ここで古い情報がゴミレコードになる
  UserProfile Exists (0.2ms)  親テーブルの重複チェック?
  UserProfile Exists (0.2ms)  親テーブルの重複チェック?
  UserProfile Load (0.2ms)  SELECT  -略- LIMIT 1
# ここで再びafter_initializeが動作している?
  UseService Load (0.2ms)  SELECT  -略- LIMIT 1 # この時点ではuse_serviceはnil
  UseLang Load (0.2ms)  SELECT  -略- LIMIT 1 # この時点ではuse_langはnil
# ここで再び動作していたafter_initializeが終わっている?
  SQL (0.2ms)  UPDATE 親テーブルのUserProfileに画像ファイルのファイル名を格納
  SQL (0.2ms)  INSERT has_oneその1に更新情報を格納
  SQL (0.2ms)  INSERT has_oneその2に更新情報を格納
COMMIT
# after_commitが動作
  UseService Load (0.2ms)  SELECT  has_oneその1の古い情報を取得
BEGIN
  SQL (0.3ms)  DELETE has_oneその1の古い情報を削除
COMMIT
  UseLang Load (0.2ms)  SELECT  has_oneその2の古い情報を取得
BEGIN
  SQL (0.3ms)  DELETE has_oneその2の古い情報を削除
COMMIT
# after_commitが終了
Redirected to http://++++
Completed 302 Found in 40ms (ActiveRecord: 10.5ms)

パーフェクトRoR買おうかな。。。