开发者

Rails 3 Shopping Cart Design Questions

I have a Transactions object (as a part of a shopping cart) that belongs_to two other objects, Products and Services. Both Products and Services are nested with Transactions to create URLs like /products/1/transactions/new and /services/1/transactions/new. And, the forms are created using form_for [@product, @transaction] do |f| type formats. Note: Products and Services are too different in design and functionality to combine them into a STI-type single object.

My question is: Is there a better way of doing this without STI? And, what's the best way to check in the controller to determine the type of object to act on?

IE in the new action:

if ???
  @product = Product.find(params[:product_id])
  @transaction = @product.transactions.build
elsif ???
  @service = Service.find(params[:service_id])
  @transaction = @service.transactions.build
end

On a related note, does anyone know of any tutorials that discuss shopping cart design for Rails 3? I've seen a few in books, but they use sessions to store the entire cart object, which isn't very secure, in my opinion. And, others are overly simplistic.

Any help would be greatly apprecia开发者_运维知识库ted!


I think you have two basic options here.

(1) Create two transaction types/models: product_transactions and service_transactions. Both can inherit from a common transaction module. This approach allows you to ignore the issue of which, "which kind of transaction am I dealing with?" and focus on the common implementation details in the transaction module. You can then maintain two simpler nested controllers, /products/<id>/transactions and /services/<id>/transactions that don't require type checking.

(2) Move the type checking into the common transaction model. This approach assumes that interactions between the transaction and product or service will be handled via the transaction module, so it won't be your responsibility to know which one you are interacting with. For example:

class Transaction
  belongs_to :service
  belongs_to :product

  def parent
    @parent ||= product || service
  end

  def call_some_action_on_parent
    parent.some_action
  end
end

You can do something similar in your controller:

@parent = params[:service_id].blank? ? Product.find(params[:product_id]) : Service.find(params[:service_id])
@transaction = @parent.transactions.build(params[:transaction])

The option you settle on should really be a decision based on your needs surrounding the transaction object. If there is a lot of custom code depending on if you are interacting with a product or service you should follow the first approach. If the code is essentially the same you should take the second approach and focus on the contract between a transaction and its parent object (product, service or other) and ignore what the object type is. In essence you are really only interested in whether or not the parent object responds to specific methods, not what kind of object it actually is. As a general rule, when possible, avoid type checking and focus on the responds_to? method instead.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜