在Rails中,如何使用accepts_nested_attributes_for创建嵌套对象?

时间:2012-08-02 13:55:33

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.2

在我的Rails应用程序中,我正在尝试为TrainingClass模型设置创建表单。我希望此表单允许用户在同一表单中创建多个ClassMeeting模型(与TrainingClass模型具有belongs_to关系),并且我使用accepts_nested_attributes_for来执行此操作。不幸的是,每当我提交表单时,都会收到错误消息:Meetings class can't be blank

我意识到这是因为ClassMeetingvalidates :class_id, presence: true,因为TrainingClass在保存之前不能拥有ID,但我不确定正确的方法绕过这个。 (我可以想到几种可能的方法,但它们并不是完全优雅的解决方案。)任何想法?我很感激你能给我的任何帮助。

注意:我发现过去曾有过一些类似的问题。但是,大多数问题都是陈旧的,并且已经过时了,而且没有一个能解决我的问题。


这是我的代码。请注意,虽然为了简洁起见,我已简化了某些方面,但ClassMeetingTrainingClass模型之间的关系却未受影响:

ClassMeeting模型:

# == Schema Information
#
# Table name: class_meetings
#
#  id         :integer         not null, primary key
#  class_id   :integer
#  start      :datetime
#  end        :datetime
#  location   :string(255)
#  created_at :datetime        not null
#  updated_at :datetime        not null
#

class ClassMeeting < ActiveRecord::Base
  attr_accessible :start, :end, :location

  validates :class_id, presence: true
  validates :start, presence: true
  validates :end, presence: true
  validates :location, presence: true, length: {maximum: 255}

  belongs_to :training_class, foreign_key: :class_id, inverse_of: :meetings
end

TrainingClass模型:

# == Schema Information
#
# Table name: training_classes
#
#  id            :integer         not null, primary key
#  description   :string(255)
#  created_at    :datetime        not null
#  updated_at    :datetime        not null
#

class TrainingClass < ActiveRecord::Base
  attr_accessible :description, :meetings_attributes

  validates :description, length: {maximum: 255}

  has_many :meetings, class_name: :ClassMeeting, foreign_key: :class_id, inverse_of: :training_class

  accepts_nested_attributes_for :meetings, allow_destroy: true
end

TrainingClasses控制器:

class TrainingClassesController < ApplicationController
  def new
    @training_class = TrainingClass.new()
    @training_class.meetings.build
  end

  def create
    @training_class = TrainingClass.new()

    if @training_class.update_attributes(params[:training_class])
        redirect_to @training_class, notice: 'Class was successfully created.'
    else
        render "new"
    end
  end
end

TrainingClass表单(查看):

<%= form_for @training_class do |f| %>
    <%= render 'shared/error_messages', object: f.object %>

    <%= f.text_area :description %>

    <h2>Schedule</h2>
    <%= f.fields_for :meetings do |meeting| %>
        <%= meeting.label :start, "Start of Meeting:" %>
        <%= meeting.text_field :start %>

        <%= meeting.label :end, "End of Meeting:" %>
        <%= meeting.text_field :end %>

        <%= meeting.label :location, "Location:" %>
        <%= meeting.text_field :location %>
    <% end %>

    <%= f.submit class:"btn btn-large btn-primary" %>
<% end %>

2 个答案:

答案 0 :(得分:0)

好吧,我找到了解决问题的方法。我需要做的就是在ClassMeeting模型中验证training_class的存在而不是class_id。这样,仍然可以验证培训课程的存在,但验证者不会干扰accepts_nested_attributes_for保存模型的方法:

class ClassMeeting < ActiveRecord::Base
  attr_accessible :start, :end, :location

  validates :training_class, presence: true # :training_class instead of :class_id
  validates :start, presence: true
  validates :end, presence: true
  validates :location, presence: true, length: {maximum: 255}

  belongs_to :training_class, foreign_key: :class_id, inverse_of: :meetings
end

答案 1 :(得分:0)

我仔细研究了这个例子,尝试了与我的代码的差异,但最后我的问题通过使用:inverse_of来解决。

请参阅accepts_nested_attributes_for child association validation failing