8
7

More than 5 years have passed since last update.

[Rails]既存サービスにhas_oneなModelを新規追加した際のデータハンドリング

Posted at

困った

既に動いているサービスに新しく機能を追加する際に、
1対1のリレーションシップを持たせたテーブルを追加する必要がありました。
例えば、usersテーブルにuser_settingsテーブルを1対1の関係で追加するってイメージです。
※usersにカラム追加すればいいじゃんってのは別の話で。

ここで困ったのが、新しく追加したテーブルへのデータ追加方法です。
考えられる方法として、
1.デプロイする際にバッチで一気にデータ投入する
2.新規追加したmodelを使う際にnullチェックをしてnullならば作成

の2パターンなんですが、
1だとデータ量が多くなっている場合にシビアになってくるので2で考えました。

しかし毎度modelを呼び出すところでnullチェックするのもめんどくさい。。

こんな実装がしたい

user.rb
#既存でデータが入っているモデルクラス
class User << ActiveRecord::Base
  has_one :user_setting
end
user_setting.rb
#新しく追加し、リレーションを組むモデルクラス
class UserSetting << ActiveRecord::Base
  belongs_to :user
  def hoge_user?
    return true
  end
end
user_controller.rb
def test
  user = User.find(params[:user_id])
  if user.user_setting.hoge_user?
    p "hogehoge"
  end
end

ここで、user_settingsテーブルに指定のuser_idのデータが入ってないと、
user_controller.rbでhoge_user?呼んでるところでぬるぽります。

そこでこんな実装をしてみた

user.rb
#既存でデータが入っているモデルクラス
class User << ActiveRecord::Base
  has_one :user_setting

  # ここを追加
  def user_setting
    UserSetting.find_or_create_by(user_id: id)
  end
end
user_setting.rb
#新しく追加し、リレーションを組むモデルクラス
class UserSetting << ActiveRecord::Base
  belongs_to :user
  def hoge_user?
    return true
  end
end
user_controller.rb
def test

  user = User.find(params[:user_id])
  if user.user_setting.hoge_user?
   puts "hogehoge"
  end
end

user.rbでuser_settingというメソッドを実装(オーバーライド)して、
そこでfind_or_create_byという読み出し時にnullの場合はcreateしてからデータを返してくれるメソッドを使い、nullでもきちんと欲しいデータが作成され取得できるようにしてみました。
ここでこだわったのがコントローラー等からはいつもどおりの読み出しかたでそれを実現したところです。

初期値とか色々いじりたかったら実装したメソッドいじればいいんじゃないですかね。

これでコントローラーやビューでデータ取得時に毎度nullチェックして作成とか意味のわからない実装しなくて済む!!

とはいえ

Railsさんなのでもうちょっと設定とかでできるんじゃねーのと思って探してて見つけれなかったのでこんな実装してみました。
これ以外にも絶対方法あると思うので誰か教えてください

8
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7