有多个答案可以解释如何拥有嵌套资源,但是,我的用例有点不同。
批处理属于订单,一个订单有很多批处理。
如果您有订单表格并且可以在该表格中创建批处理,我可以理解它是如何工作的,但无法理解适合我的情况的好方法。
我有一个嵌套资源(批处理)的表单,其中父级(订单)可能存在也可能不存在。他们可以通过单选按钮选择它是否存在。如果它存在,那么他们只需简单地选择它属于哪个订单......简单。如果它不存在,我会显示订单字段并提交订单参数和批参数。如果批处理未保存,我想确保回滚订单创建。
这是我到目前为止的代码。
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/