1

我正在構建一個配方管理器作爲第一個rails應用程序。基於這個相當不錯的ERD,我有一個多對多嵌套模型。理想情況下,我想創建一個允許我以單一形式創建配方的表單。另外,我希望用戶能夠分別將成分和步驟寫入/粘貼到單個文本字段中。在下面的代碼中,有一個虛擬屬性可以分析表單中的cr分隔列表來嘗試此操作。如何在Rails 3.1中編寫簡單的嵌套,has_many:through,多對多表單?

當我編寫配料時,我不斷收到「readonly」has_many錯誤。我明白,基於我脫機的優秀幫助,我的連接沒有正確設置。

爲簡化操作,我希望將配料列表分配到第一步或每一步。 如何編寫代碼以便使用虛擬屬性手動創建聯接模型?

我的四種模式:

recipe.rb

class Recipe < ActiveRecord::Base 
     has_many :steps, :dependent => :destroy 
     has_many :stepingreds, :through => :steps 
     has_many :ingredients, :through => :stepingreds 
     validates_presence_of :name, :description 
     attr_writer :step_instructions, :ingredient_names 
     after_save :assign_steps, :assign_ingredients 

     def step_instructions 
     @step_instruction || steps.map(&:instruction).join("\n") 
     end 

     def ingredient_names 
     @ingredient_name || ingredients.map(&:name).join("\n") 
     end 

    private 

    def assign_steps 
     if @step_instructions 
      self.steps = @step_instructions.split(/\n+/).map do |instruction| 
      Step.find_or_create_by_instruction(instruction) 
      end 
     end 
    end 

     def assign_ingredients 
     if @ingredient_names 
      self.ingredients = @ingredient_names.split(/\n+/).map do |name| 
      Ingredient.find_or_create_by_name(name) 
      end 
     end 
     end 
    end 

step.rb

class Step < ActiveRecord::Base 
     #attr_accessible :recipe_id, :number, :instructions 
     belongs_to :recipe 
     has_many :stepingreds, :class_name => 'Stepingred' 
     has_many :ingredients, :through => :stepingreds 
    end 

stepingred.rb

class Stepingred < ActiveRecord::Base 
     belongs_to :ingredient 
     belongs_to :step, :class_name => 'Step' 
    end 

ingredient.rb

class Ingredient < ActiveRecord::Base 
     has_many :stepingreds 
     has_many :steps, :through => :stepingred 
     has_many :recipes, :through => :steps 
    end 

這裏是我的精簡形式:

<%= form_for @recipe do |f| %> 
     <%= f.error_messages %> 
     <p> 
     <%= f.label :name %><br /> 
     <%= f.text_field :name %> 
     </p> 
     <p> 
     <%= f.label :description %><br /> 
     <%= f.text_area :description, :rows => 4 %> 
     </p> 
     <p> 
     <%= f.label :ingredient_names, "Ingredients" %><br /> 
     <%= f.text_area :ingredient_names, :rows => 8 %> 
     </p> 
     <p> 
     <%= f.label :step_instructions, "Instructions" %><br /> 
     <%= f.text_area :step_instructions, :rows => 8 %> 
     </p> 
     <p><%= f.submit %></p> 
    <% end %> 

我的數據庫模式:

ActiveRecord::Schema.define(:version => 20110714095329) do 
     create_table "ingredients", :force => true do |t| 
     t.string "name" 
     t.datetime "created_at" 
     t.datetime "updated_at" 
     end 
     create_table "recipes", :force => true do |t| 
     t.string "name" 
     t.text  "description" 
     t.datetime "created_at" 
     t.datetime "updated_at" 
     end 
     create_table "stepingreds", :force => true do |t| 
     t.integer "recipe_id" 
     t.integer "step_id" 
     t.integer "ingredient_id" 
     t.float "amount" 
     t.datetime "created_at" 
     t.datetime "updated_at" 
     end 
     create_table "steps", :force => true do |t| 
     t.integer "recipe_id" 
     t.integer "number" 
     t.text  "instruction" 
     t.datetime "created_at" 
     t.datetime "updated_at" 
     end 
    end 

請讓我知道如果您有任何建議或可推薦另一塊示例代碼之後我可以模擬這個應用程序。

回答

2

您需要在Recipe.rb中添加accepts_nested_attributes_for :ingredients, :stepingreds, :steps以便能夠通過一個單一的@recipe對象創建關聯的對象。

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

+0

謝謝你的回答。我添加了'accep_nested ...'並將'Ingredient.find_or_create_by_name(name)'改成了'self.steps.create(:stepingreds => [{:ingredient => {:name => name}}])''based on my my閱讀api。我現在在RecipesController中得到一個錯誤'NameError#爲#創建未定義的局部變量或方法'屬性'我是否正確寫入嵌套數組?這個錯誤告訴你什麼?日誌沒有提到試圖插入到配料表中,所以我必須創建不正確的記錄。再次感謝。 – JHo

+0

記得接受答案 – imjp

+0

很難說在沒有在應用中看到完整代碼的情況下導致此錯誤的是什麼。通常,該錯誤是在堆棧跟蹤中輸入一個行號。你能否將你的應用程序的副本推送到github存儲庫,並採取步驟正確地重現它以供我查看它? – Joey

相關問題