对象未加载

时间:2012-11-14 11:55:29

标签: ruby-on-rails ruby

这是我用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

它神奇地起作用!!!。

所以我不知道为什么会发生这种情况?...看起来商店对象在我“检查”之后才会被加载。

由于

2 个答案:

答案 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.inspectputs self.inspect之后它运作得很好?我的意思是,为什么在这种情况下不需要super来电?