Javascript Rails每次单击都会创建多个购物车记录

Javascript Rails每次单击都会创建多个购物车记录,javascript,ruby-on-rails,ajax,shopping-cart,Javascript,Ruby On Rails,Ajax,Shopping Cart,我遵循以下指南创建购物车模型: 我让它成功地工作,但仍然有一个问题。当我加载页面并添加一个项目时,如果我转到另一个页面,然后再次加载主页,则会添加一个项目,通过我拥有的侧栏菜单,我单击一个产品,相同的产品会三次添加到购物车中。我转到另一个页面并返回,每次单击5个项目,每次单击7个项目。 我不知道为什么会发生这种情况,我甚至不知道要显示代码的哪一部分,所以有人可以帮助我。 如果我重新加载页面(通过单击地址栏并输入),它会返回到每次单击添加一项 提前谢谢 编辑:在第一次评论建议之后,这里是控制器代

我遵循以下指南创建购物车模型:

我让它成功地工作,但仍然有一个问题。当我加载页面并添加一个项目时,如果我转到另一个页面,然后再次加载主页,则会添加一个项目,通过我拥有的侧栏菜单,我单击一个产品,相同的产品会三次添加到购物车中。我转到另一个页面并返回,每次单击5个项目,每次单击7个项目。 我不知道为什么会发生这种情况,我甚至不知道要显示代码的哪一部分,所以有人可以帮助我。 如果我重新加载页面(通过单击地址栏并输入),它会返回到每次单击添加一项

提前谢谢

编辑:在第一次评论建议之后,这里是控制器代码

def create
    @invoice = current_invoice
    @invoice_product = @invoice.invoice_products.new(invoice_product_params)
    @invoice.save
    session[:invoice_id] = @invoice.id
end

def update
    @invoice = current_invoice 
    @invoice_product = @invoice.invoice_products.find(params[:id])
    @invoice_product.update.attributes(order_item_params)
    @invoice_products = @invoice.invoice_products
end

def destroy
    @invoice = current_invoice 
    @invoice_product = @invoice.invoice_products.find(params[:id])
    @invoice_product.destroy
    @invoice_products = @invoice.invoice_products
end

private
def invoice_product_params
    params.require(:invoice_product).permit(:id, :invoice_id, :product_id, :price, :tax, :value)
end
同样的产品会被添加到购物车中3次。我去 另一个页面并返回,每次点击5个项目,再次每次点击7个项目 单击

这具有TurboLink和糟糕的JS绑定的所有特征

--

让我解释一下

使web应用程序中的以下链接更快。 而不是让浏览器重新编译JavaScript和CSS 在每次页面更改之间,它使当前页面实例保持活动状态和 仅替换主体(或部分)和标题中的标题。思考 CGI与持久化进程

简而言之,TurboLink使用“Ajax”加载下一页的
,替换当前的
内容。虽然这确实加快了处理速度(通过消除重新编译CSS/图像的需要),但它会对JS绑定造成严重破坏

JS“绑定”到DOM中的元素:

它希望有元素可以绑定到。这在大多数情况下都非常有效:

element = document.getElementById("your_element").addEventListener('click', function() {
   console.log('anchor');
});
但是,使用TurboLink(尤其是
JQuery
)的问题在于绑定可能会发生多次,具体取决于TurboLink将新数据加载到DOM的次数

问题是因为您的Javascript没有刷新,但是您的DOM元素正在刷新,JS将它们视为新的元素,因此每次单击都会触发函数
x
的次数。有点像我想的

--

对于您的问题,问题在于您的JS绑定:

#app/assets/javascripts/application.js
bind = function() {
    $("#shopping_cart").on("click", function(){
        //payload
    });
};
$(document).on("ready page:load", bind);
上述内容将为元素提供“本地”选择,并使用确保每次请求TurboLink时都会刷新

如果您不想在每次调用TurboLink时重新声明,只需:


控制器代码将是一个良好的开端!我发现在application.html.erb中将true%>从身体移动到头部是可行的,但这会使我的侧边栏菜单停止工作。出于某种原因,如果js事件在主体上,那么它会在每个请求上重新附加。有什么帮助吗?请回复该行并删除Turbolinks并尝试一下:无论如何,我不喜欢Turbolinks,但如果您确实想再次使用它,至少我们可以缩小问题的范围。将其移回正文并删除Turbolinks,该行现在看起来是这样的:但是,问题仍然存在。根据RichardAE的评论,删除Turbolinks有效,使你的解释完全正确。但是,我不知道如何在我的rails应用程序上实现您的解决方案,因为javascript绑定是由rails完成的。它是一个带有remote:true的表单,在提交时调用create.js.erb。我从未明确告诉它将create.js.erb中的代码绑定到该表单中的提交按钮。
#app/assets/javascripts/application.js
$(document).on("click", "#shopping_cart", function(){
   //payload
});