【问题标题】:Using transaction in Ruby On Rails controller method在 Ruby On Rails 控制器方法中使用事务
【发布时间】:2015-06-10 22:23:57
【问题描述】:

我喜欢 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

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

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

我知道“事务”是一个很好的解决方案,并且我在不同的帖子中也表示事务不应该在控制器中使用。
问题:为什么这个?

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

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

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

【问题讨论】:

    标签: ruby-on-rails ruby transactions controller rescue


    【解决方案1】:

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

    话虽如此,您的解决方案没有任何问题,但也许在您的模型(或服务层)上有方法将有助于保持控制器中的内容干净?例如User#update_x_and_create_couponUser#update_x_and_create_history_item 之类的方法。

    【讨论】:

    • 谢谢!据我了解,我最好将事务块中的所有代码包装在模型中的单个方法中,并从我的控制器内部调用该方法,以便在我的更新控制器中只剩下一个调用。我说的对吗?
    • 不一定只有一个方法,可能有多个方法,每个方法执行不同的操作。这取决于您的模型设计。
    • 没有。控制器是开始/结束事务的最佳位置,因为事务必须远离业务逻辑。通常事务由服务层或使用 .NET 或 Java 等语言处理,它们通常由服务或控制器层的拦截器处理。由于在 Rails 中,控制器(按照惯例)扮演服务层的角色,控制器是在事务中包装单个工作单元的最佳位置(如果您没有单独的服务层)
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多