2016-04-23 87 views
2

在我的應用程序中,我有一個使用實例變量的products_controller。我在Ruby中對實例變量的理解是,你可以在同一個類的不同方法中使用它們。那麼爲什麼我們在rails應用程序的多個方法中使用相同的實例變量?下面我們有一個實例變量@product設置兩次,當我們在創建操作中使用它時,新操作中的@product變量是否未被覆蓋?理解Rails實例變量

我對這些變量的範圍在同一個類的方法中有點困惑。

def new 
    @product = Product.new 
    end 

    def create 
    @product = Product.new(product_params) 

    respond_to do |format| 
     if @product.save 
     format.html { redirect_to @product, notice: 'Product was successfully created.' } 
     format.json { render :show, status: :created, location: @product } 
     else 
     format.html { render :new } 
     format.json { render json: @product.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

回答

0

在軌道控制器實例變量是從可訪問的:

  1. 當Rails控制器動作呈現視圖,該實例 變量可以在那裏進行訪問。

  2. 它也在該控制器的實例方法中可用。 (也超實例方法)

所以在這裏@productnewcreate都是指不同的實例變量。

因此,在您的案例中採取new操作的示例,變量@product可以在新窗體中訪問,因爲它是一個實例變量。

+0

這是不正確的。實例變量的作用域包括該實例的所有實例方法。 –

+0

@KeithBennett是的。我會更新我的答案。 – Alfie

0

對於類的該實例,可以在任何實例方法中訪問實例變量,。一個類的多個實例將分別擁有自己的給定實例變量副本。

您提到了newshow方法 - 您的意思是newcreate方法嗎?

請注意,所示的new方法是一種實例方法,而不是您習慣於用來實例化對象的類方法。我認爲這兩種方法的重點是隻有兩種方法中的一種用於創建給定實例,因此不存在碰撞問題。

但是,如果您調用其中一個方法,然後調用其他方法,那麼第二個方法會覆蓋第一個方法分配的值。

+0

是的,我的意思是創建,我更新了我的問題。好的,所以我們可以多次使用同一個實例變量,因爲我們調用實例方法的範圍對於我們的對象來說是不同的,所以它們不會碰到對方。我現在試圖想到一個變量可能會碰撞的例子,所以我可以更好地理解它 – adamscott

+0

當你說「我們能夠使用相同的實例變量...」時,你的意思是說你正在處理幾個實例,並且由於每個實例都有自己的實例變量,所以它們不會相互衝突,對吧?如果你想要一個類的所有實例共享的值,你可以使用類變量而不是實例變量。 –

+0

關於「我現在試圖想一個變量可能發生碰撞的例子,所以我可以更好地理解它」,你能解釋一下嗎?你的意思是一個例子,說明一個實例變量可能被覆蓋的問題。由於它旨在將範圍限定在一個對象上,因此它在別處被覆蓋的能力是一個預期的效果。 –

0

不,您無法爲所有人設置一個實例變量,直到您沒有使用before_action方法進行設置。

例如,在控制器下方,您位於索引頁面上,在創建新產品頁面後,您將在表單中看到錯誤。如未定義...

這意味着沒有設置變量爲new方法,我們在index方法調用。

def index 
    @products = Product.all 

    #adding this 
    @product = Product.new 
end 

def new 
    # leaving empty 
end 

由於create方法會發生同樣的情況。如果我們沒有定義,它會返回一個錯誤。

要設置實例變量一次,您必須使其如下所示。但它不是正確的方式,它非常混亂,並且不容易暗示。

class ProductsController < ApplicationController 
before_action :set_new_product_variable, only: [:new, :create] 

def new 
end 

def create 
    @product.title  = params[:product][:title] 
    @product.price  = params[:product][:price] 
    @product.description = params[:product][:description] 
    @product.image  = params[:product][:image] 
    @product.blabla  = params[:product][:blabla] 

    #look above its really messy and it gets bigger. Below example much more efficient, it covers everything in just one line of code. 

    @product = Product.new(product_params) 

    redirect_to @product if @product.save 
end 

private 

    def set_new_product_variable 
     @product = Product.new 
    end 
end 
2

不,它不覆蓋它。一個實例變量(@variable_name)可以在類的單個實例對象的所有方法中訪問。

現在想象一下,有一個客戶端請求「新產品路線」。 Rails會創建您的products_controller的實例對象,並調用只有該實例的new操作。該定義@product = Product.new,呈現您的new.html.erb模板,就是這樣。之後,控制器實例將被遺忘。

接下來,您的客戶點擊您的「新產品表單」的「創建產品按鈕」。另一個請求到達服務器。 Rails會創建另一個您的products_controller實例並調用create操作。 new操作未被調用。因此,您有一個新的產品實例(@product = Product.new(product_params)),其中包含表單發送的屬性。

當然,你可以從你的new行動調用create方法...

# only an example 
def new 
    @product = Product.new 
    create 
end 

...或者反過來。這會覆蓋@product變量。但爲什麼你應該這樣做?

4

實例變量在實例類範圍內。在Ruby on Rails中,由於API的構建方式,實例變量也可以在視圖中使用。

您需要注意的是,新增和創建方法通常是,用於不同的ProductsController實例

第一個請求:GET http://localhost:3000/product/new

當你問new行動(我想這是一種形式),在給定的尖軌API實現創建的ProductsController一個實例,併發送new消息到實例(調用新方法)。然後,實例變量@product將以任何方法創建並在任何視圖中以該操作呈現的形式提供。在給定的點上,Rails使用網頁進行回覆,並且類實例及其所有實例變量都被銷燬(不再可用)。

第二個請求:POST http://localhost:3000/product/create

當您提交數據庫持久的形式,又一個新的控制器實例被創建,並且create方法被調用。由於是新實例,@product沒有任何價值。

但是請注意,渲染視圖(如new操作中發生的視圖)和重定向(如果@product.save爲真,您在create操作中執行操作)之間存在差異。當你渲染時,你保持在同一個控制器實例中,當你重定向時,發生新的服務器請求,所以前面的控制器實例被銷燬並創建一個新的控制器實例。

行動之前在實際開始執行的動作代碼

before_action被調用。在Rails透視圖中,一個動作不是Ruby方法。類方法是,動作的定義是:

從滑軌引導:

控制器是一個Ruby類從ApplicationController中 繼承和具有方法就像任何其他類。當您的應用程序 收到請求時,路由將確定要運行哪個控制器和動作,然後Rails創建該控制器的實例,並且 運行與該動作同名的方法。

該動作充當由路徑確定的入口點。如果你在new中調用create,它不會再次觸發before_action。