这是我用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,并且没有使用null货币的Balance),并且生成的SQL查询是:
SELECT `balances`.* FROM `balances` WHERE `balances`.`balanceable_id` = 148 AND `balances`.`balanceable_type` = 'Store' AND `balances`.`currency` IS NULL
所以我不知道为什么......它将货币设置为NULL。 但是如果我在该过程中的任何地方放
put @ store.inspect
或default_balance
方法内部:
放置self.inspect
它神奇地起作用!!!。
所以我不知道为什么会发生这种情况?...看起来商店对象在我“检查”之后才会被加载。
由于
答案 0 :(得分:1)
Sam和Adrien正走在正确的道路上。
ActiveRecord重写method_missing以添加一大堆动态方法,包括列支持的属性(如Store#currency)的访问器。虽然我很多时候都很容易理解,但是当调用逻辑时,动态类/实例方法被添加到Store类/实例中,以便后续调用不再需要method_missing钩子。
当你在没有调用super的情况下覆盖method_missing时,你有效地禁用了这个功能。幸运的是,这个功能可以通过其他方式调用,其中一个是你在调用store#inspect时绊倒的。
通过将调用添加到super,您只需确保ActiveRecord的动态方法始终在需要时添加到类中。
答案 1 :(得分:0)
经过大量调试后终于确定了,我找到了原因......
在 Store 模型中,我有一个method_missing方法,我就是这样的:
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
end
所以当我调用self.currency
时,它首先进入method_missing,然后返回 null 。我在这里缺少的是super
电话。
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
end
但是我继续想知道为什么在我打电话给puts @store.inspect
或puts self.inspect
之后它运作得很好?我的意思是,为什么在这种情况下不需要super
来电?