gpt4 book ai didi

ruby-on-rails - Rails 4 在保存时创建关联对象

转载 作者:太空宇宙 更新时间:2023-11-03 17:31:45 24 4
gpt4 key购买 nike

如何在保存新的主对象后自动创建多个关联对象?

例如

在 Rails 4 中,我有三个对象:业务预算类别

#app/models/business.rb
class Business < ActiveRecord::Base
#attrs id, name
has_many :budgets
end

#app/models/budget.rb
class Budget < ActiveRecord::Base
#attrs id, business_id, department_id, value
belongs_to :business
belongs_to :category
end

#app/models/category.rb
class Category < ActiveRecord::Base
#attrs id, name
has_many :budgets
end

当我创建一个新业务时,在保存新业务后,我想自动为每个类别创建一个预算并为其赋予 0 美元的值(value)。这样,当我去展示或编辑新业务时,它已经具有关联的类别和预算,然后可以对其进行编辑。因此,在创建新业务时,将创建多个新预算,每个类别一个,每个预算的值为 0。

我读了这篇文章:Rails 3, how add a associated record after creating a primary record (Books, Auto Add BookCharacter)

我想知道我是否应该在业务模型中使用 after_create 回调并让逻辑存在于预算 Controller 中(不确定如何执行此操作),或者我是否应该将逻辑添加到 businesses_controller.rb使用类似于以下内容的"new"调用:

@business = Business.new
@categories = Category.all
@categories.each do |category|
category.budget.build(:value => "0", :business_id => @business.id)
end

最佳答案

根据我的经验,最好避免使用回调,除非它与给定模型的持久性相关。在这种情况下,让预算在未提供预算时设置其自己的默认值是很好地利用回调。这也消除了您逻辑中的一些复杂性。

class Budget
before_validate :set_value
...
private

def set_value
self.value ||= 0
end
end

对于其余部分,我将创建自定义类,每个类都有单一职责,以系统地生成新业务。这是一个例子。请记住,这并不是要复制和粘贴,它只是为了说明一个概念:

class BusinessGenerator < Struct.new(:business_params)

attr_reader :business

def generate
create_business
create_budgets
end

private

def create_business
@business = Business.create!(business_params)
end

def create_budgets
BudgetGenerator.new(@business).create
end
end

class BudgetGenerator < Struct.new(:business)

def generate
categories.each do |c|
business.budgets.create!(category: c)
end
end

private

def categories
Category.all
end
end

这很好,因为它分离了关注点并且易于扩展、可测试并且不使用像 accepts_nested_attributes_for 这样的 Rails 魔法。例如,如果将来您决定并非所有企业都需要每个类别的预算,您可以轻松地将所需的预算作为参数传递给 BudgetGenerator。

您将在 Controller 中实例化 BusinessGenerator 类:

class BusinessController < ActionController::Base
...
def create
generator = BusinessGenerator.new(business_params)
if generator.generate
flash[:success] = "Yay"
redirect_to generator.business
else
render :new
end
end
...
end

您可能会遇到这种方法的一些难点包括:

  • 将验证错误返回到您的业务表单
  • 如果制定预算失败,您就会陷入预算不足的困境。您不能等到创建预算后才保存业务,因为没有要关联的 ID。或许可以考虑将事务放入生成器方法中。

关于ruby-on-rails - Rails 4 在保存时创建关联对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33702536/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com