Ruby on rails 3 RAILS 3-控制器中的事务

Ruby on rails 3 RAILS 3-控制器中的事务,ruby-on-rails-3,transactions,controller,Ruby On Rails 3,Transactions,Controller,我在控制器中有一个示例操作 def some_action product = Product.new product.name = "namepro" if product.save client.update_attribute(:product_id,product.id) end end 如何为此代码添加事务?我尝试使用以下示例代码: def some_action **transaction do** product = Product.new produ

我在控制器中有一个示例操作

def some_action
 product = Product.new
 product.name = "namepro"
  if product.save
   client.update_attribute(:product_id,product.id)
  end
end
如何为此代码添加事务?我尝试使用以下示例代码:

def some_action
 **transaction do**
  product = Product.new
  product.name = "namepro"
   if product.save
    client.update_attribute(:product_create,Time.now)
   end
 **end**
end
但它会产生这样的错误:

undefined method `transaction'
我了解到在控制器中使用事务是一种不好的做法,但我不知道原因是什么()

在本例中,如果产品已创建并保存,并且客户端更新失败。。。Rails不能什么都不做


谢谢。

如果您真的愿意,您可以在控制器中使用事务。正如您所指出的,这是一种不好的做法,但如果您想这样做,只需调用
Product.transaction do
,而不是
transaction do
transaction
ActiveRecord::Base
上的类方法,因此需要在ActiveRecord派生的类上调用它。应用程序中的任何模型类都可以(吹毛求疵的警告:如果您连接到不同模型的不同数据库,这可能不是真的……但您可能没有这样做)

这是一种不好的做法的原因是它没有根据MVC范式正确地分离关注点。控制器不应该如此关注数据持久性实现。更好的方法是在
产品中添加一个方法。也许是这样的:

def save_and_update_create_time
  transaction do
    if save
      client.update_attribute(:product_create, Time.now)
    end
  end
end
然后,不要在控制器中调用
product.save
,而是调用
product.save\u和\u update\u client\u create\u time
。您可能还需要将
client
传递给该方法;从您的代码中不清楚
客户机
来自何处。如果它是
产品
上的一个属性,那么上面的方法应该有效

还有更好、更多的Railsy方法可以做到这一点,特别是如果
产品
知道其
客户端
,而不需要任何控制器数据。然后您可以使用回调,如下所示(添加到
Product
class):

然后,每次保存
产品
时,关联客户端上的字段都将更新。您可能需要首先引入一些代码来检查
客户机是否存在


除了更干净的代码外,使用回调的好处是整个回调链与save一起在单个事务中运行;您不需要手动创建事务。您可以在中阅读有关回调的更多信息。

非常感谢Jim,您的解释真的帮了我的忙!若将事务逻辑放在一个模型中,那个么事务是否会被限制在一个模型中,以不破坏独立关注点规则?通常情况下,事务跨越多个模型的可能性很高,而这些模型在DB级别上不一定相互关联。是的,我在评论的这一特定方面改变了主意。我确实喜欢不让它进入控制器的想法,但是多模型交互应该被包装在某个地方。可能是另一个类,但在某些情况下,控制器可能是正确的位置。我认为,如果需要在多个模型之间生成事务,则需要聚合根模型。马丁·福勒在这里写到了这一点
after_save :update_client

private

def update_client(product)
  product.client.update_attribute(:product_create, Time.now)
end