ActiveRecordでidがないテーブルにデータを保存しようとすると"nil is not a symbol"とか言われる
すんげハマったのでめも。
背景
create_join_table
でつくった中間テーブルのデータを更新したくて、中間テーブル用のモデルからsave!
とかupdate!
とかしようとしたわけです。
たとえば、 下記の用にOsushiクラスとNetaクラス、そして中間テーブル用のNetaOsushiクラスがあるとします。
class Osushi < ActiveRecord::Base has_many :neta_osushi end class Neta < ActiveRecord::Base has_many :neta_osushi end class NetaOsushi < ActiveRecord::Base belongs_to :osushi belongs_to :neta end
このNetaOsushiクラスのmigrationクラスは以下のようになるでしょう。
class CreateJoinTableNetaOsushi < ActiveRecord::Migration def change create_join_table :neta, :osushi do |t| t.index :neta_id t.index :osushi_id t.timestamps end end end
で、大人の事情でこのクラスのデータを更新しないといけなくなった場合に、
neta_osushi = NetaOsushi.find_by(neta_id: neta_id, osushi_id: osushi_id) # # 某かの代入などの処理 # neta_osushi.save!
とかすると、nil is not a symbol
とかすごい剣幕で怒られてしまい
「nil is not a symbol…!!!」
とみおちゃんばりの剣幕で困り果ててしまいました。
解決方法
さてこれかなりドンピシャなQiitaの記事を発見したので御覧ください。
まさにこの状況ですなー。 ということで、複合主キーを設定しましょう。
まずは、複合主キーを扱うために、composite_primary_keysというgemを入れましょう。
Gemfileに下記一行追加してbundle install
します。
gem 'composite_primary_keys', '~> 8.0.0'
ちなみにお使いのActiveRecordのバージョンによってインストールするバージョンも違うので、詳しくはcomposite_primary_keysのリポジトリのREADMEを御覧ください。
ちなみに8.xはActiveRecord4.2.x用です。
そんで、neta_osushiテーブルにunique indexをはります。
class AddIdnexToNetaOsushi < ActiveRecord::Migration def change add_index :neta_osushi, [:neta_id, :osushi_id], unique: true, name: 'composite_index' end end
最後に、モデル側で、こいつらがprimary keyだよ〜と教えてあげます。ここは、primary_key
ではなく、primary_keys
と複数なので注意。
class NetaOsushi < ActiveRecord::Base self.primary_keys = :neta_id, :osushi_id belongs_to :osushi belongs_to :neta end
これで往年の悩みは解決されました。
ゆるしてヒヤシンス!!!