我有一个Transactions对象(作为购物车的一部分),它属于另外两个对象,产品和服务。产品和服务都与事务嵌套,以创建/ products / 1 / transactions / new和/ services / 1 / transactions / new等URL。并且,使用form_for [@ product,@ transaction] do | f |创建表单类型格式。注意:产品和服务在设计和功能上的差异太大,无法将它们组合成STI类型的单个对象。
我的问题是:没有STI,有更好的方法吗?并且,检查控制器以确定要作用的对象类型的最佳方法是什么?
IE中的新动作:
if ???
@product = Product.find(params[:product_id])
@transaction = @product.transactions.build
elsif ???
@service = Service.find(params[:service_id])
@transaction = @service.transactions.build
end
在相关的说明中,有没有人知道任何讨论Rails 3购物车设计的教程?我在书中看过一些,但他们使用会话来存储整个购物车对象,我认为这不是很安全。而且,其他人过于简单化了。
非常感谢任何帮助!
答案 0 :(得分:1)
我认为你有两个基本选择。
(1)创建两个事务类型/模型:product_transactions和service_transactions。两者都可以从公共事务模块继承。这种方法可以让你忽略“我正在处理哪种交易?”的问题。并专注于事务模块中的常见实现细节。然后,您可以维护两个不需要进行类型检查的简单嵌套控制器/products/<id>/transactions
和/services/<id>/transactions
。
(2)将类型检查移动到公共事务模型中。此方法假定交易与产品或服务之间的交互将通过交易模块处理,因此您无权知道与之交互的交易。例如:
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
您可以在控制器中执行类似的操作:
@parent = params[:service_id].blank? ? Product.find(params[:product_id]) : Service.find(params[:service_id])
@transaction = @parent.transactions.build(params[:transaction])
您选择的选项应该根据您对事务对象的需求做出决定。如果您有很多自定义代码,具体取决于您是否与产品或服务进行交互,则应遵循第一种方法。如果代码基本相同,则应采用第二种方法,并专注于事务与其父对象(产品,服务或其他)之间的契约,并忽略对象类型。从本质上讲,您实际上只关心父对象是否响应特定方法,而不是它实际上是什么类型的对象。作为一般规则,尽可能避免类型检查并专注于responds_to?方法改为。