具有多种型号的 Rails 结账表
我正在根据《Agile Web Development With Rails》(版本 3)中的购物车创建一个购物车。我将其设置为将“商品”添加到“购物车”,然后在开始结帐过程时,将它们作为“line_items”添加到“订单”对象中。 “line_items”代表任意数量的一个“项目”。到目前为止,我并没有偏离书中的例子。然而,这对我来说变得复杂。我商店中的每个“商品”都可以使用文本进行自定义,并且我需要能够使用“订单”中的“line_items”存储自定义文本。
如上所述,“line_items”保存任意数量的“商品”,但客户需要能够自定义每个商品,因此每个“line_item”必须保存每个单独“商品”的不同自定义。因此,“line_items”表中不能只有一列用于自定义。我决定组织它的方式是创建一个新的模型/表“line_item_attributes”。对于“line_item”中的每个单独的“item”,都有一个新的“line_item_attributes”。
我对 Rails 还很陌生,并且在让它工作时遇到了一些困难。我什至不相信我是以“正确的方式”做这件事。我遇到的是先有鸡还是先有蛋的问题。当我创建“订单”时,我将购物车中的“商品”添加为“line_items”。现在,为了定制他们订购的产品,我还必须向每个“line_item”添加“line_item_attributes”,以便定制表单可以使用。
这是我不知道的:我不知道在客户提交表单后如何“填写”空白的“line_item_attributes”。我无法为表单创建“虚拟”line_item_attributes,然后在提交时从提交的数据创建新的(实际将保存的)。这样做的原因是它们必须绑定到它们所属的“line_items”中。我原本希望 Rails 在我调用“@order.save”时会填写它们,但事实并非如此。我希望这不难理解。
我在下面添加了相关代码:
buy.rb(控制器)
-SNIP-
def purchase
@cart = find_cart
if @cart.items.empty?
redirect_to_index("Your order is empty")
end
end
def customize
@renderable_partials = [1, 2, 3]
@order = find_order
if @order.nil?
redirect_to_index("Your order is empty")
end
end
def save_purchase
@cart = find_cart
@order = find_order(params[:cart_owner])
@order.add_line_items_from_cart(@cart)
redirect_to :action => 'customize'
end
def save_customize
@order = find_order
if @order.save
redirect_to :action => 'purchase'
else
flash[:error] = "Your information could not be saved"
redirect_to :action => 'customize'
end
end
-SNIP-
order.rb(模型)
class Order < ActiveRecord::Base
has_many :line_items
has_many :line_item_attributes
accepts_nested_attributes_for :line_items
accepts_nested_attributes_for :line_item_attributes
def add_line_items_from_cart(cart)
cart.items.each do |item|
li = LineItem.from_cart_item(item)
line_items << li
end
end
end
line_item.rb(模型)
class LineItem < ActiveRecord::Base
belongs_to :order
belongs_to :item
has_many :line_item_attributes
accepts_nested_attributes_for :line_item_attributes
def self.from_cart_item(cart_item)
li = self.new
li.item = cart_item.item
li.quantity = cart_item.quantity
li.total_price = cart_item.price
li.quantity.times do |single_item|
lia = LineItemAttribute.new
li.line_item_attributes << lia
end
li
end
end
line_item_attributes.rb(模型)
class LineItemAttribute < ActiveRecord::Base
belongs_to :order
belongs_to :line_item
end
感谢您的帮助!
I'm creating a shopping cart based on the one in Agile Web Development With Rails (version 3). I have it set up where "items" are added to a "cart", then upon starting the checkout process, they are added to an "order" object as "line_items". "line_items" represent one "item" in any quantity. Up to this point, I'm not deviating from the examples in the book. However, here is where it gets complicated for me. Every "item" in my store is customizable with text, and I need to be able to store the custom text with the "line_items" in the "orders".
As mentioned above, the "line_items" hold any quantity of an "item", but customers need to be able to customize every item, so each "line_item" will have to hold the different customizations for each individual "item". So, there cannot be just one column for the customization in the "line_items" table. The way I decided to organize it was to create a new model/table "line_item_attributes". For every individual "item" in a "line_item" there is a new "line_item_attributes".
I'm still pretty new to Rails, and I'm having some trouble getting this to work. I'm not convinced I'm even doing this the "Right Way". What I've run into is a sort of chicken/egg problem. When I create an "order", I add the "items" from the cart to it as "line_items". Now in order to customize the products they are ordering, I have to also add "line_item_attributes" to each "line_item" so that the customization form will have something to work with.
Here is what I don't know: I don't know how to "fill in" the blank "line_item_attributes" after the customer submits the form. I can't create "dummy" line_item_attributes for the form, and then upon submitting create new ones (the ones that will actually be saved) from the submitted data. The reason for this is that they must be tied into the "line_items" they belong to. I had hoped that Rails would just fill them in when I called "@order.save", but it doesn't. I hope this isn't to hard to understand.
I've included pertinent code below:
buy.rb (controller)
-SNIP-
def purchase
@cart = find_cart
if @cart.items.empty?
redirect_to_index("Your order is empty")
end
end
def customize
@renderable_partials = [1, 2, 3]
@order = find_order
if @order.nil?
redirect_to_index("Your order is empty")
end
end
def save_purchase
@cart = find_cart
@order = find_order(params[:cart_owner])
@order.add_line_items_from_cart(@cart)
redirect_to :action => 'customize'
end
def save_customize
@order = find_order
if @order.save
redirect_to :action => 'purchase'
else
flash[:error] = "Your information could not be saved"
redirect_to :action => 'customize'
end
end
-SNIP-
order.rb (model)
class Order < ActiveRecord::Base
has_many :line_items
has_many :line_item_attributes
accepts_nested_attributes_for :line_items
accepts_nested_attributes_for :line_item_attributes
def add_line_items_from_cart(cart)
cart.items.each do |item|
li = LineItem.from_cart_item(item)
line_items << li
end
end
end
line_item.rb (model)
class LineItem < ActiveRecord::Base
belongs_to :order
belongs_to :item
has_many :line_item_attributes
accepts_nested_attributes_for :line_item_attributes
def self.from_cart_item(cart_item)
li = self.new
li.item = cart_item.item
li.quantity = cart_item.quantity
li.total_price = cart_item.price
li.quantity.times do |single_item|
lia = LineItemAttribute.new
li.line_item_attributes << lia
end
li
end
end
line_item_attributes.rb (model)
class LineItemAttribute < ActiveRecord::Base
belongs_to :order
belongs_to :line_item
end
Thanks for any help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我建议将 Order 和 LineItems 创建移至单独的“服务对象”或“表单对象”。在服务/表单对象内,将订单和行项目创建包装在单个事务中。代码将更易于阅读,并且您的模型不会受到跨模型的污染。从结账控制器中,将 @cart 对象传递给服务对象,而不是直接调用 Order 对象。
有关服务对象的更多信息,请参阅本文的 #2 和 #3:http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
I recommend moving the Order and LineItems creation to a separate "service object" or "form object." Inside the service/form object, wrap the Order and Line Items creation in a single transaction. The code will be easier to read and your models will not be polluted with cross-model. From the checkout controller, pass the @cart object to the service object instead of calling the Order object directly.
Look at #2 and #3 of this post for more info about service objects: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/