了解Rails实例变量

时间:2016-04-23 19:24:43

标签: ruby-on-rails ruby

在我的应用程序中,我有一个使用实例变量的products_controller。我对Ruby中实例变量的理解是你可以在同一个类的不同方法中使用它们。那么为什么我们在rails应用程序的多种方法中使用相同的实例变量呢?下面我们有一个实例变量@product设置两次,当我们在create动作中使用它时,新动作中的@product变量是否被覆盖?

我对同一类方法中这些变量的范围感到有点困惑。

  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

5 个答案:

答案 0 :(得分:5)

实例变量位于实例类范围内。在Ruby on Rails中,由于API的构建方式,视图中也提供了实例变量。

您需要注意新的和创建方法通常在不同的ProductsController实例中使用

首次请求:获取http://localhost:3000/product/new

当您要求new操作时(我认为这是一个表单),在给定点的Rails API实现会创建ProductsController的实例,并将new消息发送到该实例instance(调用new方法)。然后,创建实例变量@product,并在任何方法或操作呈现的任何视图中可用。在给定的点上,Rails回复一个网页,并且类实例及其所有实例变量都被销毁(不再可用)。

第二次请求:发布http://localhost:3000/product/create

当您提交数据库持久性表单时,将再次创建一个新的控制器实例,并调用create方法。因为是一个新实例,所以@product没有任何价值。

但请注意,呈现视图(例如new操作中发生的视图)与重定向(如create行动中的@product.save操作之间存在差异是真的)。渲染时,您将保留在同一个控制器实例中,并且在重定向时,会发生新的服务器请求,因此会破坏先前的控制器实例并创建新的控制器实例。

之前的行动

在您实际开始执行操作代码之前调用before_action。在Rails透视图中,操作不是Ruby方法。 class方法是该操作的定义:

来自Rails指南:

  

控制器是一个继承自ApplicationController的Ruby类   和任何其他类一样有方法。当你的申请   收到请求后,路由将确定哪个控制器和   要运行的操作,然后Rails创建该控制器的实例   运行与操作同名的方法。

该行动充当由路线确定的入口点。如果你在new里面调用create,它就不会再次触发before_action。

答案 1 :(得分:3)

不,它没有覆盖它。实例变量(@variable_name)可在类的单个实例对象的所有方法中访问。

现在想象一下,客户向"新产品路线"提出了请求。 Rails创建products_controller的实例对象,并仅调用 该实例的new操作。这定义了@product = Product.new,呈现了您的new.html.erb模板及其模板。之后,控制器实例将被遗忘。

接下来,您的客户点击了"创建产品按钮"您的"新产品表格"。另一个请求到达服务器。 Rails创建了products_controller的另一个实例并调用create操作。未调用new操作。因此,您有一个新的产品实例(@product = Product.new(product_params)),其中包含表单发送的属性。

当然,您可以通过create操作...

调用new方法
# only an example
def new
  @product = Product.new
  create
end

......或者反过来说。这会覆盖@product变量。但你为什么要那样做?

答案 2 :(得分:0)

在rails控制器中,实例变量可从以下位置访问:

  1. 当Rails控制器操作呈现视图时,实例 变量可以在那里访问。

  2. 它也可以在该控制器的实例方法中使用。 (还有超类实例方法)

  3. 因此@productnew中的create都引用了不同的实例变量。

    因此,在您举例new操作的情况下,变量@product可以在新表单中访问,因为它是一个实例变量。

答案 3 :(得分:0)

实例变量可以在任何实例方法中访问,可以访问该类的实例。一个类的多个实例将各自拥有自己的给定实例变量副本。

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

请注意,显示的new方法是一个实例方法,而不是您习惯用于实例化对象的类方法。我认为这两种方法的关键是两个方法中只有一个用于创建一个给定的实例,因此没有碰撞问题。

但是,是的,如果您调用其中一个方法然后调用另一个方法,则第二个方法将覆盖第一个方法分配的值。

答案 4 :(得分:0)

不,您不能将一个实例变量设置为all,直到您没有使用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