大家好:
R隊上一篇中講到了如何通過分析請求來定位到我們要修改的模塊
但是目前我們只是定位到了代碼的位置,還沒有具體分析方法的調用關係,今天我們要進階一點,通過一個提交工單時緩存目標版本的功能爲例,弄清楚一個功能的實現具體調用了哪些方法,在弄清楚Redmine的方法調用之後,我們自然就知道應該把我們的二次開發代碼放在哪個位置了。
一. 原理分析
回顧上一篇的內容,我們已經定位到的 IssuesController的 new方法,代碼如下:
def new respond_to do |format| format.html { render :action => 'new', :layout => !request.xhr? } format.js end end
可以看到,在new方法裏沒有調用任何邏輯,但是常識告訴我們,要new一個Issue,沒有任何業務邏輯是不可能的,肯定在什麼地方隱含了一些我們目前還沒發現的邏輯。
答案就是,在 IssuesController文件的開頭,有這麼一段代碼:
before_filter :authorize, :except => [:index, :new, :create, :get_case_params, :console_log] before_filter :find_optional_project, :only => [:index, :new, :create] before_filter :build_new_issue_from_params, :only => [:new, :create]
從原理上說,這裏是通過類宏爲Controller註冊了一系列鉤子方法,感興趣的同學可以閱讀《ruby元編程》來了解詳細知識。不過目前我們只需要知道,這樣做的效果就是:Controller在調用new方法之前,先調用了 before_filter 註冊的方法。
注意before_filter的語法,before_filter這個名字表示這些方法是在調用 new之前被執行的。 第一個參數:authorize是要調用的方法的名字,第二參數有兩種:
before_filter :authorize, :except => [:index, :new, :create, :get_case_params, :console_log]
except表示除了 index、new等等這些action以外,其他的任意action執行前都需要先執行authorize
before_filter :find_optional_project, :only => [:index, :new, :create]
only則正好相反,表示只有index、new、create在調用前需要先執行find_optional_project
並且,如果有多條語句爲一個action定義了before_filter,這些被註冊的方法會按照先後順序依次執行,全部完成後纔會執行new。
二. 實現方法
現在我們知道了,原來在new一個Issue之前,需要先執行這些額外的方法,這些方法的定義,要麼來自於Helper,要麼繼承自所有Controller的父類ApplicationController,或者直接定義在controller自身之中。
現在我們用一個例子來實踐一下:提bug時根據緩存值,自動選擇目標版本。要實現這個需求,其實只需要在controller中new一個Issue之前,先給目標版本這個字段賦值即可。那麼今天所學就派上用場啦。
實現此功能的最佳方式,當然是我們自己定義一個before_filter了:
before_filter :issue_attrs_filter, :only => [:new,:edit]
在Issue new之前,先調用我們的issue_attrs_filter方法。
接下來我們要自己定義一下issue_attrs_filter這個方法,直接寫在issuesController中即可:
def issue_attrs_filter ...#邏輯處理 end
這個功能就實現了,就這麼簡單,對其他功能的代碼沒有任何影響,並且如果哪天我們不需要這個功能了,只需要註釋一行代碼即可:
# before_filter :issue_attrs_filter, :only => [:new,:edit]