在Ruby On Rails控制器方法中使用事务

MDe*_*ker 5 ruby controller transactions ruby-on-rails rescue

我喜欢Ruby On Rails,每天我都在学习和提高自己的技能.目前我正在开发一个由多个客户端使用的应用程序,我想重构我的代码,这样我就可以对代码的质量充满信心.

我正在努力实现异常处理和使用事务.我有一个控制器,必须创建和更新三个对象.以简化我的情况.

在我的控制器中:

def update
  @user.change_value_x  #(1) effects Model 'User'
  if condition == y 
    @user.create_coupon #(2) effects Model 'Coupon' via Model 'User' 
  end
  create_a_history_item #(3) effect Model 'History' 
end
Run Code Online (Sandbox Code Playgroud)

第一个(1)和第二个方法(2)位于用户模型中,第三个方法(3)也由其他控制器使用,位于/ lib目录中的Module中.所有方法都在更新/保存/创建数据库项.

如果其中一个操作失败,则所有数据库操作都应回滚并提供有关该问题的反馈.

我知道'交易'是一个很好的解决方案,我也有红色,在不同的帖子中,交易不应该在控制器中使用.
问题:这是为什么?

所以我猜这段代码不是实现事务的正确方法.

def update
  ActiveRecord::Base.transaction do
    @user.change_value_x  #(1) effects Model 'User'
    if condition == y 
      @user.create_coupon #(2) effects Model 'Coupon' via Model 'User' 
    end
    create_a_history_item #(3) effect Model 'History'
  end
  rescue
  #some code that gives feedback to user about the problem
end
Run Code Online (Sandbox Code Playgroud)

处理这个问题的最佳/正确方法是什么?

Jul*_*ier 5

事务应尽可能保持在模型级别,因为它们与模型相关,而不是与逻辑相关。控制器中的事务就像控制器中的 SQL 请求:感觉不合适。

话虽如此,您的解决方案没有任何问题,但也许在您的模型(或服务层)上使用方法有助于保持控制器中的清洁?像User#update_x_and_create_coupon和这样的方法User#update_x_and_create_history_item例如。

  • 不可以。控制器是开始/结束事务的最佳位置,因为事务必须保持在业务逻辑之外。通常事务由服务层或.NET 或Java 等语言处理,它们通常由服务或控制器层的拦截器处理。由于在 Rails 中,控制器(按照惯例)扮演服务层的角色,控制器是在事务中包装单个工作单元的最佳位置(如果您没有单独的服务层) (8认同)

小智 1

如果你愿意,你可以在你的控制器中使用Transaction,但这是一个不好的做法,但如果你想这样做,只需用User.transaction do.

这是一个不好的实践,因为它没有根据 MVC 范式正确地分离关注点。您的控制器不应该关心您的数据持久性实现。更好的方法是添加一个方法到User.