2015-11-13 88 views
1

我如何可以自動創建多個關聯的對象就在我保存新的主要對象?軌道4創建相關的對象上保存

例如

在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的值。通過這種方式,當我展示或編輯新業務時,它將已經擁有關聯的類別和預算,然後可以對其進行編輯。因此,在創建新的業務,多個新的預算將被創建,每一個類別,每一個都具有0

值我讀這篇文章:Rails 3, how add a associated record after creating a primary record (Books, Auto Add BookCharacter)

而且我想知道如果我應該使用在商業模式after_create回調,並已邏輯然後在預算控制存在(不完全知道如何做到這一點),或者我是否應該在「新」添加邏輯到businesses_controller.rb類似的東西叫:

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

看起來這裏有無關的信息,使得這個問題很難回答。除了部門預算外,企業是否真的有預算?同樣,對於部門有很多業務,反之亦然,需要有一個似乎缺失的連接表。 –

+0

謝謝。一個企業擁有多少預算。部門更像是預算類別,所以我想他們不需要與商業關聯。因此,預算是連接表。我已經更新了這個問題。如果您對實體名稱有更好的建議,請提出建議。 – Ryan

+0

我更新了問題以刪除部門和企業之間的關聯,並將部門更名爲類別。希望這會更有意義。 – Ryan

回答

0

我結束了在所有類別中添加邏輯,以在業務控制的創建方法循環並創建一個預算只保存後。請注意,我很懶,沒有進行任何錯誤處理。 :

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 
1

根據我的經驗,最好避免使用回調,除非它涉及既定模式的堅持ENCE。在這種情況下,當預算沒有提供時,讓預算設置它自己的默認值就可以很好地利用回調。這也從你的邏輯中消除了一些複雜性。

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 

這是不錯的,因爲它分離問題和易於擴展的,可測試並沒有使用Rails的魔像accepts_nested_attributes_for 。例如,如果您將來決定並非所有企業都需要每個類別的預算,則可以輕鬆地將您想要的那些作爲參數傳遞給BudgetGenerator。

你會實例化BusinessGenerator類控制器:

class BusinessController < ActiveRecord::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。也許考慮在發生器方法內部放置一個事務。
+0

這將是一個提取服務模式的好例子。 (見[#2這裏](http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/)) – dewyze

+0

可愛的答案,教會了我一些東西,謝謝! –

0

無論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外鍵是正確的。

我看你有department_idBudget belongs_to Category。你應該讓這個category_id定義foreign_key:

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