簡體   English   中英

Rails 4 在保存時創建關聯對象

[英]Rails 4 Create Associated Object on Save

如何在保存新的主要對象后自動創建多個關聯對象?

例如

在 Rails 4 中,我有三個對象: BusinessesBudgetsCategories

#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 美元。 這樣,當我去展示或編輯一個新的業務時,它已經有了相關的類別和預算,然后可以進行編輯。 因此,在創建新業務時,將創建多個新預算,每個類別一個,每個值為 0。

我讀了這篇文章: Rails 3,如何在創建主記錄后添加關聯記錄(書籍,自動添加 BookCharacter)

我想知道我是否應該在業務模型中使用 after_create 回調並將邏輯存在於預算控制器中(不完全確定如何執行此操作),或者我是否應該將邏輯添加到“新”中的 business_controller.rb調用類似於:

@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。

您將在控制器中實例化 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。 也許考慮將事務放入生成器方法中。

不管Brent Eicher的好建議如何,我從來沒有因為使用回調而遇到任何不好的事情。 如果您不介意使用它們,您可以執行以下操作(如果您每次都將預算設置為0 ):

#app/models/business.rb
class Business < ActiveRecord::Base
   before_create :build_budgets

   private

   def build_budgets
      Category.all.each do |category|
         self.budgets.build(category: category, value: "0")
      end
   end
end

——

此外,您需要確保您的budget鍵是正確的。

我看到當Budget belongs_to Category時你有department_id Budget belongs_to Category 您應該制作此category_id定義外鍵:

#app/models/budget.rb
class Budget < ActiveRecord::Base
   belongs_to :category, foreign_key: "department_id"
end

我最終將邏輯添加到業務控制器中的 create 方法以循環遍歷所有類別並在保存后創建預算。 請注意,我很懶惰,沒有進行任何錯誤處理。

  def create
    @business = Business.new(params[:business])

    @results = @business.save

    @categories = Categories.all

    @categories.each do |category|
      category.budgets.create(:amount => "0", :business_id => @business.id)
    end


    respond_to do |format|
      ...
    end
  end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM