親モデルのメソッドよりも子モデルのメソッドを先に動作させる
初期状態
子モデルに書いてあるメソッドの結果が、親モデルのプロパティに代入されるという場面がありました。
例えば。。。。
User 1----* Book
の状況で、bookの中にpriceというカラムがあり、userが所有しているbookのprice合計を、userの中のcostというカラムに代入するという仕様があったとします。また、costに入れる前にbookモデル内で消費税を自動で計算してbookのpriceに入れます。その合計をcostに入れます
(not_include_tax_priceは消費税抜きの額)
そして、そのcostのカラムが計算された後に、userのインスタンスが保存されなければならないとします。
カラムには正しい値を入れるため、before_validationをかけます。
問題
user.rb
before_validation :sum_price
def sum_price
self.cost = self.books.map{|b| b.price}.sum
end
book.rb
before_validation :sales_tax
def sales_tax
self.price = not_include_tax_price * 1.08
end
before_validation :sum_price
def sum_price
self.cost = self.books.map{|b| b.price}.sum
end
before_validation :sales_tax
def sales_tax
self.price = not_include_tax_price * 1.08
end
spec書いてましたので、そこでやりますが、、、
user = User.first
user.books.new(price: 100)
user.save
上のやり方でかくと、userのcostは消費税が勘案されていない状態で計算されます。
なぜかというと、
こちらをみていただくと、親のbefore_validaitonが働いてから、子のbefore_validaitonが働くようになっています。
ということは、def sale_taxよりもsum_priceが先に計算されることとなり、消費税が働かなくなる。。。
解決策
もうほぼ上のURLに書いてありますが、親before_saveは子before_validationの後に来ます。
ということは
before_save :sum_price
def sum_price
self.cost = self.books.map{|b| b.price}.sum
end
before_validation :sales_tax
def sales_tax
self.price = not_include_tax_price * 1.08
end
としてあげれば(sum_priceをbefore_saveに変更)、消費税がしっかり計算されてcostに入ります。
まとめ
callbackの順序を知った上で、どう実際のコーディングに落とし込むかの良い練習になりました。
Author And Source
この問題について(親モデルのメソッドよりも子モデルのメソッドを先に動作させる), 我々は、より多くの情報をここで見つけました https://qiita.com/tomoharutt/items/b065188d8a970289eba7著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .