0

There is a situation where I need to call my update action from my create action:

def create
  @product = Product.find_or_initialize_by_sku(params[:sku])
  if @product.new_record?
    respond_to do |format|
      if @product.save
        format.html { redirect_to @product, notice: 'Product was successfully created.' }
        format.json { render json: @product, status: :created, location: @product }
      else
        format.html { render action: "new" }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  else
   update ##*** I am calling the update action at this point ***##
  end
end

def update
  @product = Product.find_or_initialize_by_sku(params[:sku])

  respond_to do |format|
    if @product.update_attributes(params[:product])
      format.html { redirect_to @product, notice: 'Product was successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: "edit" }
      format.json { render json: @product.errors, status: :unprocessable_entity }
    end
  end
end

But I end up making two identical queries to my database because I am not sure of the most effective way to pass a variable (in this case, the instance variable @product) from one action to another.

I am trying to get a grasp on the 'rails' way to do this. What should I do here (as I know I should not be making two identical database queries)?

Would I store it in the session as if I was performing a redirect (Am I performing a redirect when I call an action from within another action like this?)?

session[:product] = @product # in my create action
# then
@product = session[:product] # in my update action

Does caching make this all a moot point?

4

1 回答 1

3

Consider using memoization:

@product ||= Product.find_or_initialize_by_sku(params[:sku])

The ||= operator will check if @product is nil, and if it is, Ruby will execute the finder. Otherwise, Ruby will use the current value. Therefore, when you call update from create, the update method will use the @product that you found or initialized in create.

Regarding your second question, you're not performing a redirect when you call one controller action from another. Try not to over-think it - a controller is just another Ruby class with its own instance variables (e.g. @product) and methods. To perform a redirect, you would have to call redirect_to, which would result in a second web request to your controller.

于 2012-12-16T07:19:47.070 回答