2012-11-14 14 views
5

これはルビー/レールで私に起こった最も奇妙なことです。オブジェクトがロードされない

私はモデルを持っています。これは、残高です。そして、私は店の通貨に基づいてデフォルトのバランスを与える方法を持っています。

ストアモデル。

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 

[OK]を、作用を示すので、その後のバランスコントローラに私が持っている、それは私の特定のバランスやデフォルトのものを提供します。

バランスコントローラ。奇妙な部分が出番私は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 /記憶/ 148 /バランス/デフォルト

(通貨がヌルに設定されたため、ヌル通貨とはバランスが存在しない)、これはnullを返す、および生成されたSQLクエリは次のとおりです。

SELECT `balances`.* FROM `balances` WHERE `balances`.`balanceable_id` = 148 AND `balances`.`balanceable_type` = 'Store' AND `balances`.`currency` IS NULL 

それはNULLとして通貨を設定している理由...だから私は知りません。そのプロセスにおける任意の場所で、私は置けばしかし

またはdefault_balanceメソッド内store.inspect @置く:

がself.inspectを置く

それは魔法のように動作します!!!

私はなぜそれが起こっているのかわかりません... ... "inspect"とかそういうものまでストアオブジェクトがロードされていないようです。

ありがとうございました

+0

'currency'はテーブルストアの列ですか? – Yanhao

+0

はい、そうです。 'currency:string(255)' – esbanarango

+0

クエリの前にオブジェクトをデバッグしようとします。 –

答えて

0

最終的には多くのデバッグの後に、私は理由を見つけました...ストアモデルで

私はmethod_missingメソッドを持っていると私はこのようにそれを持っていた:私はそれがmethod_missingに最初に行き、その後、ヌルを返さself.currencyを呼んでいたので、

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 

を。私がここで欠けていたのは、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コールが必要でないのか?

+1

おそらく、 'inspect'はテーブルのすべてのカラムのメソッドを定義する呼び出しを行うためです。 –

+0

Adrien is right-'inspect'はあなたの暗黙のうちに降下する' Object'で定義されています。 'method_missing'は、クラスやその祖先にメソッドが見つからない場合にのみ呼び出されます。 –

1

SamとAdrienは正しいパスにあります。

ActiveRecordは、Store#currencyのような列を持つ属性のアクセサを含む動的メソッドの全体を追加するために、method_missingをオーバーライドします。ロジックが呼び出されたときに、動的クラス/インスタンスメソッドがStoreクラス/インスタンスに追加され、後続の呼び出しでもmethod_missingフックが不要になると言うだけで十分です。

superを呼び出さずにmethod_missingをオーバーライドすると、この機能が実質的に無効になります。幸いにも、この機能は他の手段で呼び出すことができます。そのうちの1つは、store#inspectを呼び出したときにトリップしたものです。

superにコールを追加するだけで、ActiveRecordの動的メソッドが必要なときにクラスに常に追加されることが保証されました。

関連する問題