【发布时间】: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
我现在通过 create 和 update 操作调用 Student.init(student_params)。
这种方法的唯一缺点是,即使学生创建失败,它也会创建教室。对于我的应用程序来说,这并不重要。
【问题讨论】:
标签: ruby-on-rails nested-forms has-many-through