Rails 4.1升级至5.1后使用acts_as_shopping_cart gem遇price_cents属性错误
price_cents 缺失的错误 嘿,我之前帮朋友排查过类似的Rails版本升级后和旧gem兼容的问题,结合你遇到的ActiveModel::MissingAttributeError,大概率是两个核心问题:要么是购物车条目模型缺字段,要么是老版本gem跟不上Rails 5.1的API变化。下面给你一步步的排查和解决思路:
1. 先确认数据库里有没有price_cents字段
这个acts_as_shopping_cart gem默认是用price_cents(整数类型,存分的数值)来存储购物车条目的价格的。你先检查下:
- 打开
db/schema.rb,找shopping_cart_items表,看看有没有price_cents这一列。 - 如果没有,赶紧生成迁移补上:
rails generate migration AddPriceCentsToShoppingCartItems price_cents:integer rails db:migrate
别小看这个,很多时候升级后忘了同步旧gem依赖的字段就会出这错。
2. 检查模型的gem宏配置是否正确
确保你的两个核心模型配置对了:
- 购物车主模型(比如
ShoppingCart)要加acts_as_shopping_cart:
class ShoppingCart < ApplicationRecord acts_as_shopping_cart end
- 购物车条目模型(比如
ShoppingCartItem)要加acts_as_shopping_cart_item:
class ShoppingCartItem < ApplicationRecord acts_as_shopping_cart_item end
另外,你的商品模型(比如Product)必须有price方法,gem会调用这个方法来给购物车条目赋值price_cents。如果你的商品存的是元(比如price字段是decimal类型的9.99),那得把它转成分(999)返回,或者直接在商品模型里加个price_cents方法:
class Product < ApplicationRecord def price_cents (price * 100).to_i end end
3. 解决gem和Rails 5.1的兼容性问题
说实话,acts_as_shopping_cart 0.4.1是2015年的老版本了,Rails 5.1在2017年才出,两者的ActiveRecord属性赋值逻辑有不少变化。这里有两个方案:
方案A:换个兼容Rails 5的fork版本
官方gem已经很久没更了,但社区有不少fork适配了新Rails版本。你可以在Gemfile里指定一个靠谱的fork,比如:
gem 'acts_as_shopping_cart', github: 'jonhue/acts_as_shopping_cart'
然后跑bundle update acts_as_shopping_cart更新一下,这个fork我之前用过,支持Rails 5+。
方案B:手动修改gem代码适配
如果不想换fork,你可以自己改gem的代码:
- 先找到gem的安装路径:
bundle show acts_as_shopping_cart - 打开
lib/acts_as_shopping_cart/shopping_cart.rb,找到add方法,看它是怎么给条目赋值price_cents的。Rails 5.1对属性赋值的校验更严,原代码可能直接用item.price_cents = ...,你可以改成item[:price_cents] = ...或者确保属性在模型的attribute_names里。
4. 检查控制器的强参数和逻辑
看你的错误栈指向shopping_carts_controller.rb的add_to_cart方法,你要确保:
- 不是手动创建购物车条目时漏传了
price_cents参数; - 如果是用gem的
add方法,那就确保传入的商品对象能正确返回价格(比如前面说的price或price_cents方法)。
举个例子,控制器里的代码应该类似这样:
def add_to_cart product = Product.find(params[:product_id]) @shopping_cart.add(product) # gem会自动从product取价格 redirect_to shopping_cart_path, notice: '商品已加入购物车' end
5. 用控制台快速排查
打开rails console,手动模拟添加操作,看具体在哪一步报错:
cart = ShoppingCart.create! product = Product.first cart.add(product)
如果控制台里直接报错,那问题肯定在模型层,不用纠结控制器了。这时候可以直接看cart.add的源码(跑cart.method(:add).source能看),一步步调试赋值逻辑。
内容的提问来源于stack exchange,提问作者Sonalkumar sute

