ruby-on-rails - 使用事务在 Controller 操作中创建 2 个模型 - Rails 4

标签 ruby-on-rails ruby ruby-on-rails-4 activerecord

有多个答案可以解释如何拥有嵌套资源,但是,我的用例有点不同。

批处理属于订单,一个订单有很多批处理。

如果您有订单表格并且可以在该表格中创建批处理,我可以理解它是如何工作的,但无法理解适合我的情况的好方法。

我有一个嵌套资源(批处理)的表单,其中父级(订单)可能存在也可能不存在。他们可以通过单选按钮选择它是否存在。如果它存在,那么他们只需简单地选择它属于哪个订单......简单。如果它不存在,我会显示订单字段并提交订单参数和批参数。如果批处理未保存,我想确保回滚订单创建。

这是我到目前为止的代码。

def create
  @batch = Batch.new(batch_params)

  Batch.transaction do
    if params[:new_order] == "newOrder"
      @order = Order.new(order_params)
      @order.project_id = params[:batch][:project_id]
      begin
        @order.save!
      rescue
        respond_to do |format|
          format.html { render action: 'new' }
          format.json { render json: {order: @order.errors}, status: :unprocessable_entity }
          format.js { render json: {order: @order.errors}, status: :unprocessable_entity }
        end
        raise ActiveRecord::Rollback
        return
      end
      #@batch.order_id = @order.id
    end

    respond_to do |format|
      begin
        @batch.save!
        format.html { redirect_to @batch, notice: 'Batch was successfully created.' }
        format.json { render json: @batch }
        format.js { render json: @batch }
      rescue
        binding.pry
        raise ActiveRecord.Rollback
        format.html { render action: 'new' }
        format.json { render json: {batch: @batch.errors}, status: :unprocessable_entity }
        format.js { render json: {batch: @batch.errors}, status: :unprocessable_entity }
      end
    end
  end
end

这与我想要的不太一样,看起来很丑陋。我有一种感觉,我正在让它变得比我需要的更困难。在这种情况下最好的方法是什么?非常感谢!

最佳答案

这似乎是使用服务对象的好机会:https://www.engineyard.com/blog/keeping-your-rails-controllers-dry-with-services .

此模式对于保持模型和 Controller 的清洁以及确保应用程序的这些部分遵守单一职责原则非常有用。

在这种情况下,我会做的是创建一个名为 CreateBatch 的服务类,它接收参数并针对每种情况执行正确的逻辑。然后您可以在 Controller 中呈现正确的输出。这也将有助于清理您拥有的有条件和提前返回。

例如:

# app/controllers/batches_controller.rb
def create
  project_id = params[:batch][:project_id]
  new_order = params[:new_order]

  result = CreateBatch.new(new_order, batch_params, order_params, project_id).call

  if result.errors
    # handle errors with correct format
  else
    # handle successful response with correct format
  end
end

# app/services/create_batch.rb
class CreateBatch

  def initialize(new_order, batch_params, order_params, project_id)
    @new_order = new_order
    @batch_params = batch_params
    @order_params = order_params
    @project_id = project_id
  end

  def call
    if new_order?
      create_new_order
    else
      add_batch_to_existing_order
    end
  end

  private

  def new_order?
    @new_order
  end

  def create_new_order
    order_params = @order_params.merge(project_id: @project_id)
    Order.save(order_params)
  end

  def add_batch_to_existing_order
    Batch.create(@batch_params)
  end
end

我没有运行它,所以它可能需要一些调整才能工作,但是,我希望这是一个好的起点。这个重构的一个很棒的事情是你现在有 1 个逻辑条件和 1 个响应条件,不需要添加 Transaction block ,也没有提前返回。将 call 方法分成 2 个可以从 Controller 调用的不同方法可能是有意义的。使用这样的服务类也使代码更容易进行单元测试。

关于ruby-on-rails - 使用事务在 Controller 操作中创建 2 个模型 - Rails 4,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56842412/

相关文章:

java - 自动将 Java 正则表达式转换为 Ruby 正则表达式?

python - 如何在 Django 中实现基本身份验证

ruby - 如何对数组的所有元素执行 bool 运算并将结果混合在一起?

ruby - 经常将 irb 历史刷新到文件

ruby-on-rails - 有没有一种惯用的方法来执行 where(params[ :foo] || '*' ) in Rails?

ruby-on-rails - 累积 Chartkick 图表和 Acts_As_Taggable_On

ruby-on-rails - 从另一个 View 渲染一个 View

ruby - 用Ruby编写DSL的教程

sql - 如何使用 Join 而不是 Rails 4 中的子查询来编写此 ActiveRecord 查询

ruby-on-rails-4 - rails 4 wicked pdf 缺少模板