2010-01-24 110 views
4

我遇到了某種範圍問題,它阻止了實例變量被從視圖中調用的助手正確初始化。Ruby on Rails:使用視圖助手初始化實例變量

#sample_controller.rb 
class SampleController < ApplicationController 
    def test 
    end 
end 

#application_controller.rb 
helper_method :display 
def display 
    if not defined? @display 
    return @display = "a" 
    else 
    return @display += "a" 
    end 
end 

#test.html.erb 
<%= display %> 
<%= display %> 
<%= @display %> 
<%= @display.reverse %> 

當顯示樣本/測試時,它會在「評估nil.reverse」時死亡並顯示錯誤。這是令人驚訝的,因爲前兩個顯示的調用應該已經初始化@display,我會想到的。如果<%= @ display.reverse%>被移除,則輸出爲「a aa」,表示@display實例變量已由輔助方法設置,但在視圖中無法訪問它。

如果控制器修改,從而成爲(與原始視圖代碼):

class SampleController < ApplicationController 
    def test 
    display 
    end 
end 

輸出成爲「AA AAA一個一個」。如果我讓它在控制器中顯示2個電話,我會得到「aaa aaaa aa aa」。因此,似乎只有在控制器中進行的調用纔會修改SampleController實例變量,而視圖中的調用將修改視圖無法訪問的ApplicationController的實例變量。

這是一個在Rails中的錯誤還是我誤解,這是由於某種原因的預期功能?

我碰到這個bug的上下文是試圖創建一個logged_in? ApplicationController方法,它在第一次調用時設置@user變量,如果用戶登錄,則返回true或false。除非在視圖中使用它之前在控制器中添加了不必要的調用,否則這將不起作用。

回答

6

有兩種@display高德在渲染時,一個控制器和一個視圖。視圖無法訪問控制器中的視圖,反之亦然。在渲染開始時,Rails將所有控制器ivars複製到視圖中。但是在那個時候@display不存在,不會被複制過來。在任何ruby程序中,對@my_undefined_ivar的調用將返回零 - 這正是發生在您身上的事情。

可能會令人困惑,這裏有另一種說法。 Rails將ivars從控制器複製到渲染開始處的視圖中。因此,視圖的伊娃變化並不反映在控制器伊娃,反之亦然。你定義的helper允許視圖在控制器上調用一個方法,這樣控制器的ivar可以作爲返回值傳遞迴視圖,但是對控制器ivar本身的改變並不反映在另一個視圖的ivar中。

在這種情況下只需使用助手方法,並忘記視圖中的@display。

+0

因此,在我的真實應用程序中,@display實際上是@user,它用於顯示有關用戶的信息。舉個例子,我的意思是,典型的代碼就像<%if logged_in?%><%= @ user.name%><%end%>。那麼最好的方法是在ApplicationController中設置@user變量來執行before_filter調用?因爲經常,對於給定的視圖,@user的唯一用途就像我上面概述的那樣,並且沒有其他需要在控制器中使用它。 – 2010-01-24 21:48:30

+0

是的,伊娃拷貝機制符合您所描述的內容。在過濾器之前設置@user。 – ffoeg 2010-01-24 21:57:30

+0

謝謝@ffoeg,這個回答非常有幫助。你可以指向任何文檔或導軌指南,這是解釋? View,Controller和Helpers之間共享什麼變量尚不清楚。 – CodeKid 2016-09-17 21:15:48

0

我認爲這可能是第二reserved words問題這個星期我見過...

提示:你幾乎不必使用Ruby中return關鍵字。此外,您的defined?使用被嚇到我了......可能是值得嘗試這樣的:

if @display.nil? 
    @display = "a" 
    else 
    @display += "a" 
    end 
+0

你在這裏看到什麼是保留字問題?無論如何,我猜這不是最基本的問題,因爲我最初遇到了使用所有不同單詞(登錄像我所提到的)的錯誤以及我在這裏生成的代碼來弄清楚什麼是錯誤。 感謝您對return語句的提示。 定義?我用過的似乎在做我的意圖,但不是嗎?我從authlogic的示例實現代碼中獲得了它,他們將它用於類似的目的。 – 2010-01-24 19:55:53

+0

根據保留字列表,「顯示」已知會引起問題。我從來沒有聽說過在視圖中定義實例變量的問題,因爲大多數登錄模式完全按照您在這裏嘗試執行的操作,在第一次調用current_user時定義@current_user。界定?在技​​術上會在這裏工作,但它通常用於引發錯誤的事情,而不是如果未定義則返回nil,如局部變量和方法定義。零?適用於實例變量檢查的常見情況,並且稍微易於解析。 – tfwright 2010-01-24 20:51:08