这是使用ruby / rails发生在我身上的最奇怪的事情。
我有一个模型, 商店 ,其中有许多余额 。 而且我有一种方法可以根据商店的货币为我提供默认余额。
商店模型。
class Store < ActiveRecord::Base has_many :balances, as: :balanceable, dependent: :destroy def default_balance #puts self.inspect <- weird part. balances.where(currency: self.currency)[0] end ... end平衡模型。
class Balance < ActiveRecord::Base belongs_to :balanceable, :polymorphic => true ... end好吧,那么在Balance控制器中我有show动作,这会给我一个特定的余额或默认值。
平衡控制器。
class Api::Stores::BalancesController < Api::Stores::BaseController before_filter :load_store # Returns a specific alert # +URL+:: GET /api/stores/:store_id/balances/:id def show #puts @store.inspect <- weird part. @balance = (params[:id] == "default") ? @store.default_balance : Balance.find(params[:id]) respond_with @balance, :api_template => :default end ... private # Provides a shortcut to access the current store def load_store @store = Store.find(params[:store_id]) authorize! :manage, @store end end现在这里是奇怪的部分来...
如果我打电话给节目操作; 例如:
GET / api / stores / 148 / balances / default
它返回null(因为货币被设置为null,并且没有Balance为空货币),并且生成的SQL查询是:
SELECT `balances`.* FROM `balances` WHERE `balances`.`balanceable_id` = 148 AND `balances`.`balanceable_type` = 'Store' AND `balances`.`currency` IS NULL所以我不知道为什么......它将货币设置为NULL。 但如果我在那个过程中的任何地方放了
puts @ store.inspect
或者在default_balance方法中:
提出自己的看法
它神奇地工作!!!。
所以我不知道为什么会发生这种情况?......看起来商店对象没有被加载,除非我“ 检查 ”它或类似的东西。
谢谢
This is the weirdest thing ever happened to me with ruby/rails.
I have a model, Store, which has_many Balances. And I have a method that gives me the default balance based on the store's currency.
Store model.
class Store < ActiveRecord::Base has_many :balances, as: :balanceable, dependent: :destroy def default_balance #puts self.inspect <- weird part. balances.where(currency: self.currency)[0] end ... endBalance model.
class Balance < ActiveRecord::Base belongs_to :balanceable, :polymorphic => true ... endOk, so then in the Balance controller I have the show action, that will give me a specific balance or the default one.
Balance controller.
class Api::Stores::BalancesController < Api::Stores::BaseController before_filter :load_store # Returns a specific alert # +URL+:: GET /api/stores/:store_id/balances/:id def show #puts @store.inspect <- weird part. @balance = (params[:id] == "default") ? @store.default_balance : Balance.find(params[:id]) respond_with @balance, :api_template => :default end ... private # Provides a shortcut to access the current store def load_store @store = Store.find(params[:store_id]) authorize! :manage, @store end endNow here is where the weird part comes...
If I make a call to the show action; for example:
GET /api/stores/148/balances/default
It returns null (because the currency was set as null, and there is no Balance with null currency), and the SQL query generated is:
SELECT `balances`.* FROM `balances` WHERE `balances`.`balanceable_id` = 148 AND `balances`.`balanceable_type` = 'Store' AND `balances`.`currency` IS NULLSo I DON'T know why... it is setting the currency as NULL. BUT if in any where in that process I put
puts @store.inspect
or inside the default_balance method:
puts self.inspect
it magically works!!!.
So I don't know why is that happening?... It seems like the store object is not getting loaded until I "inspect" it or something like that.
Thanks
最满意答案
萨姆和阿德里安走在正确的道路上。
ActiveRecord覆盖method_missing以添加一大堆动态方法,包括支持列的属性(如Store#货币)的访问器。 虽然我在这方面做了很多工作,但足以说明,当调用逻辑时,动态类/实例方法将被添加到Store类/实例,以便后续调用不再需要method_missing挂钩。
如果您在不调用super的情况下覆盖method_missing,则会有效地禁用此功能。 幸运的是,此功能可以通过其他方式调用,其中一种方式是在您调用store#inspect时触发的其中一种方法。
通过添加对super的调用,您只需确保ActiveRecord的动态方法总是在需要时添加到类中。
OK finally after a lot of debugging, I found the reason...
In the Store model I have a method_missing method and I had it like this:
def method_missing method_name, *args if method_name =~ /^(\w+)_togo$/ send($1, *args).where(togo: true) elsif method_name =~ /^(\w+)_tostay$/ send($1, *args).where(tostay: true) end endSo when I was calling self.currency it went first to the method_missing and then returned null. What I was missing here was the super call.
def method_missing method_name, *args if method_name =~ /^(\w+)_togo$/ send($1, *args).where(togo: true) elsif method_name =~ /^(\w+)_tostay$/ send($1, *args).where(tostay: true) else super end endBut I continue wondering why after I had called puts @store.inspect or puts self.inspect it worked well?. I mean, why in that case that super call wasn't needed?
更多推荐
发布评论