简体   繁体   English

Rails:更新购物车中的数量

[英]Rails: Updating quantities in shopping cart

Ruby newbie here. Ruby新手在这里。 I'm going through Agile Web Development With Rails. 我正在通过Rails进行敏捷Web开发。 In chapter 11 it challenges you to add a 'decrease quantity' button to items in the shopping cart. 在第11章中,它要求您为购物车中的商品添加“减少数量”按钮。 I went ahead and tried to implement an increase link as well. 我继续尝试实施增加链接。

The problem is it's not doing anything when I click on the links. 问题是当我点击链接时它没有做任何事情。

line_items_controller.rb 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 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 的routes.rb

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

_line_item.html.erb _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 /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 /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);
}

Let me know if I forgot anything crucial. 如果我忘记任何重要的事情,请告诉我。 Thanks in advance! 提前致谢!

----EDIT---- - - 编辑 - -

I changed the code to what Rich posted, and this is what shows up in the console when I click the '+' link. 我将代码更改为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"):

So I see that it needs a route for qty but I'm not quite sure how to set that up. 所以我看到它需要一个数量的路线,但我不太确定如何设置它。 I'm guessing the JS alert we set up isn't firing because it's snagging up at this point? 我猜测我们设置的JS警报没有解雇,因为它在这一点上陷入困​​境?

----EDIT 2---- ----编辑2 ----

Now I'm passing the links as POST and getting this name error, from both the up and down links: 现在我将链接作为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'

What confuses me here is that current_cart works in the increase and decrease methods but not in qty . 让我感到困惑的是, current_cartincreasedecrease方法中起作用,但在qty起作用。

With this type of pattern, you're best DRY ing up your logic into a single action: 对于这种类型的模式,你是最好的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

This will allow you to pass a single link (with the potential of qty ) to your controller. 这将允许您将单个链接(具有可能的qty )传递给您的控制器。 If you leave it blank, it will just use 1 as the 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 %>

Debugging 调试

Since you're new, you need to understand about debugging . 既然你是新手,你需要了解调试

When doing something like this, there are many places it could "go wrong". 在做这样的事情时,有很多地方可能“出错”。 Like many inexperienced devs, you've basically said "it's not working"... the problem is that many experienced devs know that there has to be a problem somewhere. 像许多没有经验的开发者,你基本上说:“它不工作” ......问题是,许多有经验的开发者知道,必须问题的地方。

The best thing you can do is find out where it's going wrong. 你能做的最好的事情是找出它出错的地方。 This is a tedious process (test each part); 这是一个繁琐的过程(测试每个部分); you should start with your JS: 你应该从你的JS开始:

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

If the above fires, it means you're doing everything right up to that point . 如果上述火灾,这意味着你做的一切权利到这一点

If you add the above file with my recommended code, we'll have a much better idea as to what the problem may be. 如果您使用我推荐的代码添加上述文件,我们将更好地了解问题所在。 You'll also want to post your console logs for the requests sent to your line_items controller (this will indicate whether Rails treats the request as successful). 您还需要发送控制台日志以查找发送到line_items控制器的请求(这将指示Rails是否将请求视为成功)。

Once you've found the problem, you can then pinpoint what needs to be done to fix it, which is where many people expect a question to be based. 一旦找到问题,您就可以确定需要采取哪些措施来解决问题,这是许多人期望问题的基础。


As an aside, we've built a cart before (it uses sessions rather than db): 顺便说一句 ,我们之前已经构建了一个购物车 (它使用的是会话而不是数据库):

在此输入图像描述

I could write up how to do it if you want. 如果你愿意,我可以写出如何做到这一点。 It uses a session-based model . 它使用基于会话的模型


Update 更新

The error you're seeing is because you're sending a GET request through your link; 您看到的错误是因为您通过链接发送了GET请求; my routes were POST & DELETE respectively. 我的路线分别是POSTDELETE You need something like the following: 您需要以下内容:

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

I think I got it wrong in my post (apologies) - you have to make sure you're passing the method as POST or DELETE 我认为我的帖子中有错误(道歉) - 你必须确保你将method作为POSTDELETE传递


Update 2 更新2

To initialize the current_cart method, you need to make sure you have it available. 要初始化current_cart方法,您需要确保它可用。

Ryan Bates alludes to this in his "Session Model" Railscast -- Ryan Bates在他的“会话模型”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

Some time passed since you asked this - did you solved it? 你问过这个问题已经过去了一段时间 - 你解决了吗? I have one answer to this issue - I managed to increase/decrease numbers in cart, but without Ajax calls - everytime button clicked - page reloads (I removed remote: true ). 我对这个问题有一个答案 - 我设法增加/减少购物车中的数字,但没有Ajax调用 - 每次点击按钮 - 页面重新加载(我删除了remote: true )。 I have not followed @Richard Peck solution, even dough it might be a better way. 我没有关注@Richard Peck解决方案,甚至可能是更好的方式。 So, as he pointed out, routes had to use get method, instead of put (I am not very sure why get instead of post should be used, but if Rails asks it I kindly do it): 因此,正如他指出的那样,路由必须使用get方法,而不是put (我不太清楚为什么get而不是post应该使用,但是如果Rails问它我很友好):

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

Also, I have been noticed by other guy on StackExchange that i forgot to allow increase / decrease actions in controller, since we restrict most of them by default: 此外,StackExchange上的其他人注意到我忘了在控制器中允许increase / decrease操作,因为我们默认限制大部分操作:

line_items_controller.rb : line_items_controller.rb

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

So, I guess these two issues was your problem (just like mines). 所以,我猜这两个问题是你的问题(就像地雷一样)。

line_items_controller.rb: 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 : 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

and links: 和链接:

<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>

Would this make what you need? 这会成为你需要的吗? And maybe any ideas why Ajax is not working? 也许任何想法为什么Ajax不起作用? Here a link to full my question: 这是一个完整我的问题的链接:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM