rails勉強メモ5 – nill or null? allow_nil?blank? gemfileとgemfile.lockの関係性, dependentについて –

nilとnullの話

nil null
rails 存在する 存在しない
DB 存在しない 存在する
  • railsにnullは存在しない、DBにnullは存在する
  • railsにnilは存在する、DBにnilは存在しない

Rails側でnilを入れるとDBにはnullが入る

allow_nilとallow_blankを調べる

一言で言うとallos_blankの方がガバガバ。allow_nil + ‘’(空文字)って言う感じ。

nil ‘’(空文字)
allow_nil: true 通る 通らない
allow_blank: true 通るやん 通る

ちなみにフロントからバックにデータを送る方法は formajax の2つの方法があるが、どちらもnullやnil(フロントにはないけど)を送る方法は存在しない。
formで何も入力せずに送っても必ず空文字に変換され、ajaxで以下のようにnullを送っても空文字に変換される。

gemfileとgemfile.lockの話

概要
gemfileをインストールするときに依存関係を表すもの
依存関係とはどのgemがどのgemに依存しているかということと、インストール時にverが何だったかを記録するもの


どういうことかをverにfocusして記述する。
gemfileの書き方には以下の用にgemのverを指定しない書き方gemのverを指定する書き方`がある。

この状態でbundle installするとverを指定しない方はその時点でのrailsの最新のverが入り、verを指定している方は指定しているverが入る(例: 4.2)

基本的にverを指定している場合は問題は怒らない。
問題はverを指定していないときに起こる。

複数人で管理するとverが異なるようになってしまう。
例えば以下のようにverを指定しないでgemfileを記述する。

ここでAさんがbundle install をおこなってrails 4.2が入ったとする。
半年後、Bさんがプロジェクトに入り、gemfileだけをもらい、bundle installしてみた。
そうすると、その時点での最新のverが入るため、rails 5.1 が入ってしまい、二人の環境が違う状態になってしまいてんやわんやみたいなことになってしまう。

このようにインストールするタイミングで各々の環境にあるgemのverが違うようになってしまってはダメである。

Gemfile.lockがそれを解決してくれる
Gemfile.lockにはbundle installした時のver情報がすべて記述されている。
もちろん、あるgemをインストールするために必要なgemのver情報も全てである。

このファイルが有ることによって先ほどのBさんはbundle installするとGemfile.lockの情報を元にgemがインストールされるのでAさんと同じ状況を作り出すことが出来るのだ。

bundle updateの話
上記から考えると、bundle updateというインストールしているgemのverをあげるという行為は、gemfileに記述してあるgemのリストのupdateを確認し、最新verをインストールし、gemfile.lockを更新しているのである。

これがlockファイルの役目である。
JSのyarn.lockなども同じなのではなかろうか(確信はない)

アプリケーションレベルとDBレベルのdependentの話

Railsでは has_manyhas_oneなどを使用してモデル同士の関係を表す。
この際に関係の親レコードが消されたときに子レコードに対しての処理は以下のようなものがある。

  • 親が消えたら子.destroyを呼んで子も消える(dependent: :destroy)
  • 親が消えたらDBから直接、子を消す(dependent: :delete or delete_all)
  • 親が消えても子は残る(外部キーにnullを入れてレコードを残す(dependent: :nullify))

ここではひとつづつ解説する。
また簡単にUserモデルとProfileモデル(user_idを外部キーに持つ)を考える
これは登録しているユーザーがプロフィールデータを持っているようなよくあるアプリケーションである。

親が消えたら子も消える
まず、親が消えたら子も消してしまうパターンの2つを考える。
この場合は dependent: :destroy or delete, delete_allを使用する。
deleteとdelete_allの違いはhas_oneかhas_manyかの違い。

前者のdestroyを呼ぶパターンはアプリケーションから削除命令を出すため、ROLLBACKや、さらにprofileの子がいた場合もdependentが反映される。
また、destroyを呼ぶということはprofileのインスタンスを作成→削除という流れなのでDBから直接削除よりも効率が悪い。

DBから直接呼ぶパターンはROLLBACKなども起こらない
また、インスタンスを生成しないのでdependent: :destroyよりも早い。

つまり、子を削除する前に何か処理を行いたい(子に紐づく孫モデルの削除を行いたいとか)場合は、dependent: :destroyを指定し、そうでない場合はdependent: :deleteを使えばいいんじゃないかなぁと思っている。
ただ、孫モデルを作ったときに親モデルで指定したdependent: :deleteをdestroyに変更し忘れそうなのでdestroyでいいんじゃないかなぁとも思いました。

親が消えても子は残る
これは外部キーにnullを入れてレコードを残すパターン。
例えば、子レコードの外部キーにnullが入っていても問題ない場合はnullifyにして残しても良い。

railsとDBの対応表
ちなみに上記のコードをDBレベルの制約で言うと以下のようになる。

rails destroy, delete, delete_all restrict_with_(exception or error) nullify
DB CASCADE RESTRICT, NO ACTION SET NULL

スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

スポンサーリンク