Rails4でSTIのモデルのform_forで詰まった話
STI on rails
railsはSTIをサクッと実装する方法を提供してくれているので,
type columnに子供のクラス名を指定するだけです.
# app/model/product.rb class Product < ApplicationRecord end # app/model/product/smart_phone.rb class Product::SmartPhone < Product end # app/model/product/pc.rb class Product::Pc < Product end # app/model/product/tablet.rb class Product::Tablet < Product end p = Product.new(type: 'Product::SmartPhone') p.class.name #=> Product::SmartPhone
問題
# config/routes.rb resources :products # app/views/products/_form.html.slim # @product = Product.where(type: 'Product::SmartPhone').first # @product.class.name #=> Product::SmartPhone = form_for @product do |f| ....
STIの親クラス名でroutingを定義している時に,
edit画面で, 子クラスのobjectをform_forの引数に渡すと..
rails に product_smart_phone_path を探しに行かれてundefinedになって死ぬ.
最終解決策
= form_for @product.becomes(Product) do |f|
結論への紆余曲折
最初は form_for 内で url_for が呼ばれてるんだろどうせと思い,
railsのgithub repositoryで url_for を検索して code 読みまくった.
(ここでrails のアーキテクチャのわかってなさを痛感...)
そしてurl_forにobject渡した時は
ActiveModel::Nameのインスタンスが帰ってきて
そのインスタンスに対してmethod呼び出しをして
呼び出すpathが決まる事を知った.
そこで
class Product::SmartPhone << Product def self.model_name superclass.model_name end end
とやって無理やり子クラスのurl_forの値を親クラスのものに
していた.
が正しい事をやってるかんが全くない &&
これだけのために大掛かりなことをしすぎてる感
があって結局 becomesに