🧤

ActiveHashの落とし穴 (EOTD No.3)

2020/12/02に公開

こちらはAmetaです!the Error Of The Day(EOTD)の三回目です。

今回は目次機能を使ってみました!


本日のエラー

ActionView::Template::Error (undefined method 'delivery_days_id' for #<Item:~>)

シチュエーション

ActiveHash[1]を用いて商品宅配日数を直接データベースに保存することなく管理するための実装です。

エラ-メッセージにある"delivery_day_id"というのは、Itemテーブルという商品を管理するテーブルに保存されているものです。

商品が届くまでにかかる日数を3パターン(1日後,2~3日後,4~7日後)に固定したので、ActiveHash::Base[2]を継承させたクラス(DeliveryDay)にハッシュで記述しました。

class DeliveryDay < ActiveHash::Base
  self.data = [
    { id: 1, name: '--' },
    { id: 2, name: '1日後' },
    { id: 3, name: '2~3日後' },
    { id: 4, name: '4~7日後' }
  ]

itemモデル、そしてdelivery_dayモデルにもアソシエーションの記述をしてっと。

models/item.rb
class Item < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :delivery_day
  
  validates :delivery_days_id, numericality: { other_than: 1, message: "can't be blank" }
models/delivery_day.rb
class DeliveryDay < ActiveHash::Base
  self.data = [
    { id: 1, name: '--' },
    { id: 2, name: '1日後' },
    { id: 3, name: '2~3日後' },
    { id: 4, name: '4~7日後' }
  ]
  include ActiveHash::Associations
  has_many :items
end

最後にdelivery_dayをビューファイルで呼び出す記述。

<%= @item.delivery_day.name %>

このビューファイルに遷移しようとした所、今回のエラーがおきました。。。

ActionView::Template::Error (undefined method 'delivery_days_id' for #<Item:~>)

考察

delivery_days_idが定義されていないメソッドなので、それを必要とするdelivery_daysメソッドが動いてくれないということなのか...?

でもデータベースのItemテーブルにはdelivery_days_idがカラムとして管理されてるのに。。

しばらく考え、休すかと思いきや...

一つ怪しいところを見つけました!

解決

Itemモデルにある記述です。

class Item < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :delivery_day
  
  validates :delivery_days_id, numericality: { other_than: 1, message: "can't be blank" }

お分かりいただけたでしょうか。。

belongs_to_active_hash :delivery_day

validates :delivery_days_id

この二つの記述が一致していないという点。
さらに言えば、delivery_day.rbにあるクラス(DeliveryDay)とdelivery_days_idの部分が一致していない。

これが今回のエラーの原因じゃないかということで、モデルとコントローラーにある記述を修正。そして、データベースも一度ロールバックしてマイグレーションをし直しました。

再度試してみると...。通りました!!

原因(おそらく)

ここまで済んだ後に思い出したのが、delivery_day.rbのモデルを作る時のコマンドがdelivery_daysとなってしまっていたことです。

rails g model delivery_days

モデル名は自動でdelivery_day.rbに変換されたみたいですが、データベースにそのまま反映してしまったようでした。

SOTD(Summary of the day)

モデル名は単数形というルールをうっかり忘れてしまった結果、かなり時間を取られました。

規約を守ることが効率的な開発への近道!今日の学びです。

脚注
  1. 後から変わらないようなデータをモデルに記述することで、データベースに直接保存しないで管理させてくれるgem。 ↩︎

  2. ActiveHashに定義されているクラス。.allや.findなどのActiveRecordメソッドを使えるようにしてくれる。 ↩︎

Discussion