[英]Rails: Updating quantities in shopping 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 %> ×</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);
}
如果我忘记任何重要的事情,请告诉我。 提前致谢!
- - 编辑 - -
我将代码更改为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
在increase
和decrease
方法中起作用,但在qty
起作用。
对于这种类型的模式,你是最好的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是否将请求视为成功)。
一旦找到问题,您就可以确定需要采取哪些措施来解决问题,这是许多人期望问题的基础。
顺便说一句 ,我们之前已经构建了一个购物车 (它使用的是会话而不是数据库):
如果你愿意,我可以写出如何做到这一点。 它使用基于会话的模型 。
更新
您看到的错误是因为您通过链接发送了GET
请求; 我的路线分别是POST
和DELETE
。 您需要以下内容:
<%= link_to "-", line_items_qty_path(line_item), method: :post, remote: true %>
我认为我的帖子中有错误(道歉) - 你必须确保你将method
作为POST
或DELETE
传递
更新2
要初始化current_cart
方法,您需要确保它可用。
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
你问过这个问题已经过去了一段时间 - 你解决了吗? 我对这个问题有一个答案 - 我设法增加/减少购物车中的数字,但没有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不起作用? 这是一个完整我的问题的链接:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.