【问题标题】:How to Write a Simple Nested, has_many :through, many-to-many Form in Rails 3.1?如何在 Rails 3.1 中编写简单的嵌套、has_many :through、多对多表单?
【发布时间】:2011-10-07 12:06:07
【问题描述】:

我正在构建一个食谱管理器作为第一个 Rails 应用程序。我有一组基于这个非常好的ERD 的多对多嵌套模型。理想情况下,我想创建一个表单,允许我以单一表单创建食谱。此外,我希望用户能够将成分和步骤分别写入/粘贴到单个文本字段中。在下面的代码中,有一个虚拟属性会解析表单中的 cr 分隔列表来尝试这样做。

当我编写成分时,我不断收到“只读”has_many 错误。我了解,基于我离线的出色帮助,我的加入设置不正确。

为了简化事情,我想将成分列表分配给第一步或每一步。 如何编写代码以便手动创建具有虚拟属性的连接模型?

我的四个模型:

食谱.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

成分.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

如果您有任何建议或可以推荐另一段示例代码,请告诉我,我可以模仿这个应用程序。

【问题讨论】:

    标签: many-to-many nested-forms has-many-through ruby-on-rails-3.1


    【解决方案1】:

    您需要在Recipe.rb 中添加accepts_nested_attributes_for :ingredients, :stepingreds, :steps 才能通过单个@recipe 对象创建关联对象。

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

    【讨论】:

    • 感谢您的回答。我添加了accepts_nested...,并根据我对api的阅读将Ingredient.find_or_create_by_name(name)更改为self.steps.create( :stepingreds =&gt; [ { :ingredient =&gt; {:name =&gt; name} } ] )。我现在收到 #<0x9114cf0>
    猜你喜欢
    • 2011-10-22
    • 2013-12-24
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 2011-06-06
    • 1970-01-01
    相关资源
    最近更新 更多