Rails:更新购物车中的数量

时间:2016-01-30 16:41:39

标签: javascript ruby-on-rails ruby cart

Ruby新手在这里。我正在通过Rails进行敏捷Web开发。在第11章中,它要求您为购物车中的商品添加“减少数量”按钮。我继续尝试实施增加链接。

问题是当我点击链接时它没有做任何事情。

line_items_controller.rb

def decrease
  @cart = current_cart
  @line_item = @cart.decrease(params[:id])

  respond_to do |format|
    if @line_item.save
      format.html { redirect_to store_path, notice: 'Item was successfully updated.' }
      format.js { @current_item = @line_item }
      format.json { head :ok }
    else
      format.html { render action: "edit" }
      format.json { render json: @line_item.errors, status: :unprocessable_entity}
    end
  end
end

def increase
  @cart = current_cart
  @line_item = @cart.increase(params[:id])

  respond_to do |format|
    if @line_item.save
      format.html { redirect_to store_path, notice: 'Item was successfully updated.' }
      format.js   { @current_item = @line_item }
      format.json { head :ok }
    else
      format.html { render action: "edit" }
      format.json { render json: @line_item.errors, status: :unprocessable_entity }
    end
  end
end

cart.rb

def decrease(line_item_id)
  current_item = line_items.find(line_item_id)
  if current_item.quantity > 1
    current_item.quantity -= 1
  else
    current_item.destroy
  end
  current_item
end

def increase(line_item_id)
  current_item = line_items.find(line_item_id)
  current_item.quantity += 1
  current_item
end

的routes.rb

resources :line_items do
  put 'decrease', on: :member
  put 'increase', on: :member
end

_line_item.html.erb

<% if line_item == @current_item %>
<tr id="current_item">
<% else %>
<tr>
<% end %>
  <td><%= line_item.quantity %> &times;</td> 
  <td><%= line_item.product.title %></td>
  <td class="item_price"><%= number_to_currency(line_item.total_price) %></td>
  <td><%= link_to "-", decrease_line_item_path(line_item), method: :put, remote: true %></td>
  <td><%= link_to "+", increase_line_item_path(line_item), method: :put, remote: true %></td>
  <td><%= button_to 'Remove Item', line_item, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>

/line_items/increase.js.erb

$('#cart').html("<%= escape_javascript(render(@cart)) %>");
$('#current_item').css({'background-color':'#88ff88'}).animate({'background-color':'#114411'}, 1000);

/line_items/decrease.js.erb

$('#cart').html("<%= escape_javascript(render(@cart)) %>");
$('#current_item').css({'background-color':'#88ff88'}).animate({'background-color':'#114411'}), 1000);
if ($('#cart tr').length==1) {
  // Hide the cart
  $('#cart').hide('blind', 1000);
}

如果我忘记任何重要的事情,请告诉我。提前谢谢!

---- ---- EDIT

我将代码更改为Rich发布的内容,这是我点击“+”链接时显示在控制台中的内容。

Started GET "/line_items/25/qty" for ::1 at 2016-01-30 23:49:11 -0600

ActionController::RoutingError (No route matches [GET] "/line_items/25/qty"):

所以我看到它需要一个数量的路线,但我不太确定如何设置它。我猜测我们设置的JS警报没有解雇,因为它在这一点上被抓了?

----编辑2 ----

现在我将链接作为POST传递,并从上下链接中获取此名称错误:

Started POST "/line_items/25/qty" for ::1 at 2016-01-31 09:49:04 -0600
Processing by LineItemsController#qty as JS
  Parameters: {"id"=>"25"}
Completed 500 Internal Server Error in 38ms (ActiveRecord: 0.0ms)

NameError (undefined local variable or method `current_cart' for #<LineItemsController:0x007fbfb11ea730>):
  app/controllers/line_items_controller.rb:70:in `qty'

让我感到困惑的是,current_cart适用于increasedecrease方法,但不适用于qty

2 个答案:

答案 0 :(得分:2)

使用这种类型的模式,您最好将DRY逻辑转换为单一操作:

#config/routes.rb
resources :line_items do
   match :qty, action: :qty, via: [:post, :delete], on: :member #-> url.com/line_items/qty
end

#app/models/line_item.rb
class LineItem < ActiveRecord::Base
   after_update :check_qty, if: "qty_changed?"

   private

   def check_qty
     self.destroy if self.qty.zero?
   end
end 

#app/controllers/line_items_controller.rb
class LineItemsController < ApplicationController
   def qty
      @cart = current_cart
      @item = @cart.line_items.find params[:id]

      if request.post? #-> increment
         method = "increment"
      elsif request.delete? #-> decrement
         method = "decrement"
      end

      @item.send(method, :qty, params[:qty])

      respond_to do |format|
          if @item.save
             format.html { redirect_to store_path, notice: 'Item was successfully updated.' }
             format.js   { @current_item = @line_item }
             format.json { head :ok }
          else
             format.html { render action: "edit" }
             format.json { render json: @line_item.errors, status: :unprocessable_entity}
         end
     end
   end
end

这将允许您将单个链接(潜在的qty)传递给您的控制器。如果你把它留空,它只会使用1作为数量:

 <%= button_to "+", line_items_qty_path(@line_item), params: { qty: 5 } %>

 <%= link_to "-", line_items_qty_path(line_item), method: :post, remote: true %>
 <%= link_to "+", line_items_qty_path(line_item), method: :delete, remote: true %>

<强>调试

由于您是新手,因此您需要了解调试

当做这样的事情时,有很多地方可能“出错”。像许多缺乏经验的开发人员一样,你基本上都说“它不起作用”......问题是许多经验丰富的开发人员都知道 在某个地方存在问题。

你能做的最好的事情就是找出问题所在。这是一个繁琐的过程(测试每个部分);你应该从你的JS开始:

#app/views/line_items/qty.js.erb
alert("test");

如果上述情况发生,则意味着您在到目前为止一切正常

如果您使用我推荐的代码添加上述文件,我们可以更好地了解问题所在。您还需要发送控制台日志以查找发送到line_items控制器的请求(这将指示Rails是否将请求视为成功)。

一旦找到问题,您就可以确定需要采取哪些措施来解决问题,这是许多人希望问题的基础。

顺便说一下,我们之前built a cart(它使用的是会话而不是数据库):

enter image description here

如果你愿意,我可以写出如何做到这一点。它使用session-based model

<强>更新

您看到的错误是因为您通过链接发送了GET个请求;我的路线是POST&amp;分别为DELETE。您需要以下内容:

 <%= link_to "-", line_items_qty_path(line_item), method: :post, remote: true %>

我认为我的帖子中有错误(道歉) - 您必须确保将method作为POSTDELETE

传递

更新2

要初始化current_cart方法,您需要确保它可用。

Ryan Bates在"Session Model" Railscast -

中暗示了这一点
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
   before_filter :current_cart
   helper_method :current_cart

   private

   def current_cart
     @current_cart = session[:cart_id] ? Cart.find(session[:cart_id]) : Cart.create
     session[:cart_id] = @current_cart.id if @current_cart.new_record?
   end
end

答案 1 :(得分:2)

自从你问这个问题以来已经过去了一段时间 - 你解决了吗?我对这个问题有一个答案 - 我设法增加/减少购物车中的数字,但没有Ajax调用 - 每次点击按钮 - 页面重新加载(我删除了remote: true)。我没有关注@Richard Peck解决方案,甚至可能是更好的方式。因此,正如他所指出的,路线必须使用get方法,而不是put(我不太清楚为什么应该使用get而不是post,但是如果Rails问我好心吗):

  resources :line_items do
    get 'decrease', on: :member
    get 'increase', on: :member
  end

此外,StackExchange上的其他人注意到我忘记在控制器中允许increase / decrease个操作,因为我们默认限制大部分操作:

<强> line_items_controller.rb

  before_action :set_cart, only: [:create, :decrease, :increase]

所以,我猜这两个问题是你的问题(就像地雷一样)。

line_items_controller.rb:

  def decrease
    product = Product.find(params[:product_id])
    @line_item = @cart.remove_product(product)

    respond_to do |format|
      if @line_item.save
        format.html { redirect_to cart_path, notice: 'Line item was successfully updated.' }
        format.js
        format.json { render :show, status: :ok, location: @line_item }
      else
        format.html { render :edit }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

  def increase
    product = Product.find(params[:product_id])
    @line_item = @cart.add_product(product)

    respond_to do |format|
      if @line_item.save
        format.html { redirect_to :back, notice: 'Line item was successfully updated.' }
        format.js
        format.json { render :show, status: :ok, location: @line_item }
      else
        format.html { render :edit }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

<强> cart.rb

  def add_product(product)
    current_item = line_items.find_by(product_id: product.id)
    if current_item
      current_item.quantity += 1
    else
      current_item = line_items.build(product_id: product.id)
    end
    current_item
  end

  def remove_product(product)
    current_item = line_items.find_by(product_id: product.id)
    if current_item.quantity > 1
      current_item.quantity -= 1
    elsif current_item.quantity = 1
      current_item.destroy
    end
    current_item
  end

和链接:

<td><%= link_to "-", decrease_line_item_path(product_id: line_item.product), class:"btn btn-danger" %></td>
<td><%= link_to "+", increase_line_item_path(product_id: line_item.product), class:"btn btn-success" %></td>

这会成为您需要的吗?也许任何想法为什么Ajax不起作用?这里有一个完整问题的链接:

https://stackoverflow.com/questions/40551425/rails-ajax-jquery-cant-make-to-render-changes-without-page-refresh