Rails 4 嵌套形式 - 嵌套模型不保存

Rails 4 nested form - nested models not saving

我正准备放弃这个...我已经搜索了所有关于这个的问题,做了多次测试,但我无法弄明白。

我正在尝试通过嵌套属性(教室 -> 学生)创建模型(缺勤)的新记录。

这是我手动创建并在调用

时保存的散列
# hash: {"classroom"=>{"rank"=>"aaa", "grade_id"=>"", "students_attributes"=>{"0"=>{"last_name"=>"aaa", "first_name"=>"aaa", "absences_attributes"=>{"0"=>{"class_time"=>"1", "status"=>"valid"}}}}}, "id"=>"26"} 

@classroom = Classroom.find(params["id"])
@classroom.update(params["classroom"])

这给了我:

(0.5ms)  begin transaction
SQL (1.3ms)  UPDATE "classrooms" SET "rank" = ?, "updated_at" = ? WHERE "classrooms"."id" = ?  [["rank", "aaa"], ["updated_at", "2016-08-10 21:09:17.883875"], ["id", 26]]
SQL (0.2ms)  INSERT INTO "students" ("last_name", "first_name", "classroom_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["last_name", "aaa"], ["first_name", "aaa"], ["classroom_id", 26], ["created_at", "2016-08-10 21:09:17.897997"], ["updated_at", "2016-08-10 21:09:17.897997"]]
SQL (0.2ms)  INSERT INTO "absences" ("class_time", "status", "student_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["class_time", 1], ["status", "Αδικαιολόγητη"], ["student_id", 51], ["created_at", "2016-08-10 21:09:17.902018"], ["updated_at", "2016-08-10 21:09:17.902018"]]
(11.4ms)  commit transaction
=> true 

然而

当我通过表单提交获得此哈希时,更新不会发生,也不会创建 "absences"。控制台如下所示:

Processing by ClassroomsController#update as HTML 
Parameters: {"utf8"=>"✓", "authenticity_token"=>"blabla", 
"classroom"=>{"students_attributes"=>{"0"=>{"absences_attributes"=>{
"0"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"1", "status"=>"valid"}, 
"1"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"2", "status"=>"valid"}, 
"2"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"3", "status"=>"valid"}, 
"3"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"4", "status"=>"valid"}, 
"4"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"5", "status"=>"valid"}, 
"5"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"6", "status"=>"valid"}, 
"6"=>{"student_id"=>"50", "date"=>"2016/08/17", "class_time"=>"7", "status"=>"valid"}}, 
"id"=>"50"}}}, "id"=>"27"} 
Classroom Load (0.2ms) SELECT "classrooms".* FROM "classrooms" WHERE "classrooms"."id" = ? LIMIT 1 [["id", 27]] 
(0.1ms) begin transaction Student Load 
(0.3ms) SELECT "students".* FROM "students" WHERE "students"."classroom_id" = ? AND "students"."id" = 50 [["classroom_id", 27]] 
(0.1ms) commit transaction

这是我的教室控制器

class ClassroomsController < ApplicationController

  def new
    @classroom = Classroom.new
    @students = 30.times {@classroom.students.build}
  end

  def create
    @classroom = Classroom.new(classroom_params)
    if @classroom.save
      redirect_to @classroom
    else
      flash.now[:danger] = "Try again."
      render "new"
    end
  end

  def show
    @classroom = Classroom.find(params[:id])
  end

  def data
    @classroom = Classroom.find(params[:id])
    @classroom.students.each { |student| 7.times { student.absences.build } }
  end

  def update
    @classroom = Classroom.find(params[:id])
    @classroom.update_attributes(classroom_params)
    redirect_to @classroom
  end

  private
    def classroom_params
      params.require(:classroom).permit(:id, :grade_id, :rank, students_attributes: 
        [:id, :classroom_id, :first_name, :last_name, absences_attributes: 
        [:id, :student_id, :date, :status, :class_time]])
    end
end

课堂模型

class Classroom < ActiveRecord::Base
  # belongs_to :grade
  has_many :students, inverse_of: :classroom, dependent: :destroy
  accepts_nested_attributes_for :students, allow_destroy: true,
  reject_if: proc { |a| [a[:first_name], a[:last_name]].any? {|b| b.blank?}}

  has_many :absences, through: :students
  accepts_nested_attributes_for :absences, allow_destroy: true,
  reject_if: proc { |a| a[:status].blank? }

  validates :rank, presence: true
end

学生模型

class Student < ActiveRecord::Base
  belongs_to :classroom, inverse_of: :students
  has_many :absences, inverse_of: :student

  accepts_nested_attributes_for :absences, allow_destroy: true,
  reject_if: proc { |a| a[:status].blank? }

  # validates :first_name, presence: true
  # validates :last_name, presence: true

  def full_name
    return last_name + " " + first_name
  end
end

缺席模型

class Absence < ActiveRecord::Base
  belongs_to :student, inverse_of: :absences

  # validates :date, presence: true
  # validates :class_time, presence: true
  # validates :status, presence: true, inclusion: { in: ["valid",
  #   "invalid", "erased"] }
end

我已关闭所有验证,以确保这不是它们未被保存的原因。

嵌套表单视图

<div id="absences" class="tab-pane fade in active">
  <h3>Absences</h3>
  <br>
  <div class="input-group date col-md-3" id="datepicker">
    <input type="text" class="form-control">
    <div class="input-group-addon">
      <span class="glyphicon glyphicon-th"></span>
    </div>
  </div>
  <%= form_for @classroom do |class_f| %>
    <% @classroom.students.each do |student| %>
      <div class="student_<%= student.id %>">
        <h4><%= student.full_name %></h4>
        <div class="absences">
          <p>
            <% 7.times do |i| %>
              <span><%= i + 1 %></span>
            <% end %>
          </p>
          <%= class_f.fields_for :students, student do |student_f| %>
            <% student.absences.each_with_index do |absence, i| %>
              <div class="school-hour text-center" data-value="<%= i + 1 %>">
                <%= fa_icon "plus" %>
                <%= fa_stacked_icon "plus", base: "circle-o" %>
                <%= fa_icon "minus" %>
                <%= student_f.fields_for :absences, absence do |ab_f| %>
                  <%= ab_f.hidden_field :student_id, value: absence.student_id %>
                  <%= ab_f.hidden_field :date, class:"input-absence-date" %>
                  <%= ab_f.hidden_field :class_time, value: i + 1 %>
                  <%= ab_f.hidden_field :status, class:"input-absence-status" %>
                <% end %>
              </div>
            <% end %>
          <% end %>
        </div>
      </div>
    <% end %>

    <div class="actions">
      <%= button_to "Submit", "#", class:"btn btn-primary"%>
    </div>

  <% end %>
</div>

没有值的隐藏字段在提交表单之前通过 javascript 填充。我认为这与问题无关。 params hash 通过了,但是没有保存。

没有花很多时间看这个,这可能是问题所在吗?

reject_if: proc { |a| a[:status].blank? }

似乎参数传递的状态为 "".blank? 评估为 true

无论您的表单传入什么,在您的第一个示例中您都有 "status"=>"valid" 但在您的第二个示例中来自表单 "status"=>""

我发现问题出在教室模型上的 reject_if。

我试图通过 user 更新 absence,我实际上并没有更改 user 的名称,因此没有将其作为参数传递。结果记录没有通过 reject_if: proc { |a| [a[:first_name], a[:last_name]].any? {|b| b.blank?}} 所以它根本没有达到缺席记录。我试着放一个 :new_record? reject if 中的验证以及其他检查,但没有成功。

我在这个答案中找到了解决方案: 很棒而且干净。也看看评论