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.
精彩评论