【问题标题】:Creating associated has_many :through records with nested forms创建关联的 has_many :through 带有嵌套表单的记录
【发布时间】:2015-05-16 02:07:41
【问题描述】:

以下是我的多对多关系中的模型:

class Student < ActiveRecord::Base
  has_many :classroom_memberships, :dependent => :destroy
  has_many :classrooms, :through => :classroom_memberships
end

class ClassroomMembership < ActiveRecord::Base
  belongs_to :classroom
  belongs_to :student
end

class Classroom < ActiveRecord::Base
  has_many :classroom_memberships
  has_many :students, :through => :classroom_memberships
end

在创建新学生时,我希望用户能够选择多个教室并且还可以即时创建新教室

(我已经能够让它处理一对多的关系。)

这是我目前在学生表单中的内容:

<%= f.association :classrooms,
  collection: Classroom.all(order: 'name'),
  prompt: "Choose or type a new classroom name",
  multiple: true,
  input_html: { :class => "shown" } %>

这让我可以做这个漂亮的多选框(使用 selectize.js):

当我提交表单时,通过的参数是:

=> {
     "first_name" => "Tyene",
      "last_name" => "Sand",
       "birthday" => "January 1, 2013",
         "gender" => "F",
       "about_me" => "",
      "family_id" => "1",
  "classroom_ids" => [
    [0] "",
    [1] "1",
    [2] "2"
  ]
}

当调用Student.new(student_params) 时,Rails 神奇地知道在classroom_memberships 表中创建 2 条新记录,一切顺利。

即时创建新教室

但是,如果我让用户将一个全新的教室添加到列表中,Rails 会抛出此错误:

Couldn't find all Classrooms with IDs (1, 2, 0) (found 2 results, but was looking for 3)

如果不首先为选择列表中的第三项创建新的classroom,它显然无法创建classroom_memberships 记录。

我的问题:

如何(或在哪里)插入一些代码来检查参数中的 classroom_ids 列表并在 Rails 检查 classroom_id 是否存在之前创建 classroom 记录?

我尝试将代码放入 classroom_membershp.rb 模型中,如下所示:

  def classroom_id=(val)
    # if we've got an integer, they selected an existing record;
    # otherwise, we're creating a brand new one
    if val.numeric?
      write_attribute(:classroom_id, val.to_i)
    else
      create_classroom(:name => val)
    end
  end

但代码永远不会到达这里!它试图在此之前通过SELECT 找到classroom 并炸毁。这种方法在一对多关系中对我很有效。

感谢@lx00st 的回答,我最终得到了什么:

/app/models/student.rb:

  def self.init(params)
    params[:classroom_ids].each_with_index do |c, i|
     # a non-blank, non-numeric classroom ID indicates a new record
     if !c.blank? && !c.numeric?
        params[:classroom_ids][i] = Classroom.create(:name => c).id
      end
    end
    new(params)
  end

我现在通过 createupdate 操作调用 Student.init(student_params)

这种方法的唯一缺点是,即使学生创建失败,它也会创建教室。对于我的应用程序来说,这并不重要。

【问题讨论】:

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


    【解决方案1】:

    我会在 Student 类中使用一些特殊的 self.init(params) 方法

    def self.init(params)
      if i = params[:classroom_ids].find_index(&:empty?)
        params[:classroom_ids][i] = create_classroom 
      end 
      new(params)
    end
    

    【讨论】:

    • 好的,我认为这可行。我必须在这里添加一个迭代器,以防多个新教室被创建并且create_classroom 也需要参数。
    • 谢谢!我根据您的回答用我得出的解决方案更新了我的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 2011-10-01
    • 2011-02-17
    相关资源
    最近更新 更多