ruby-on-rails-3 – Rails 3和has_many:through:在连接模型上
我深入搜索了网页,以便找到一个干净简单的方法来处理has_many:through关系的连接模型上的属性初始化,但我没有找到满足我需要的最佳解决方案.
在下面提供的exaple中,我需要在创建或更新Course对象时自动设置Training join模型的属性角色. 这是我的模特: QUALIFICATIONS = ["Theoretical Instructor","Practical Instructor"] class Course < ActiveRecord::Base has_many :trainings,dependent: :destroy has_many :theoretical_instructors,through: :trainings,source: :trainer,conditions: { "trainings.role" => "Theoretical Instructor" } accepts_nested_attributes_for :theoretical_instructors has_many :practical_instructors,conditions: { "trainings.role" => "Practical Instructor" } accepts_nested_attributes_for :practical_instructors end class Trainer < ActiveRecord::Base has_many :trainings,dependent: :destroy has_many :courses,through: :trainings end class Training < ActiveRecord::Base belongs_to :trainer belongs_to :course # Join model has the :role attribute,that I wish I could validate this way: # validates :role,presence: true,inclusion: { in: QUALIFICATIONS } end 这个模型背后的基本原理是我想将Training对象保存在一个表中.我不想创建TheoreticalInstructor和PracticalInstructor连接模型(可能爆炸表的数量)来解决这个问题. 此视图提供了提交新课程的表单: <%= form_for @course do |course_form| %> <%- # fields for course attributes,as usual... %> <%= course_form.label :theoretical_instructor_ids %><br /> <%= course_form.select :theoretical_instructor_ids,Trainer.all.map { |x| [[x.name,x.surname].join(" "),x.id] },{ },{ multiple: true } %> <%= course_form.label :practical_instructor_ids %><br /> <%= course_form.select :practical_instructor_ids,{ multiple: true } %> <%= course_form.submit %> <% end%> 问题是:为了使@course = Course.new(params [:course])能够在课程控制器中唯一的代码行在提交上一个表单时保存这个关联,我能做些什么? 与this question不同,我不想在创建新课程时创建新的Trainer对象:我想从已经存在于DB中的那些(通过多选输入字段)中选择它们. 我需要的是像@ course.theoretical_instructor_ids = [1,2]之类的东西创建两个Training对象,其role属性设置为Theory Instructor 我正在考虑关于训练的after_initialize回调,它基于关系名称(:theoretical_instructors和:practical_instructors)设置角色,但我真的不知道该怎么做.有什么建议?我错过了一些观点吗? 感谢你们! 来自oli-g的编辑1 This question处理类似的问题:区别在于我不想在创建新课程时构建Trainer对象,但我只想将现有的Trainer对象与新课程相关联. 编辑2来自oli-g 基于this(5岁的帖子)和this博客文章,我以这种方式更改了课程模型: class Course < ActiveRecord::Base has_many :trainings,conditions: ["trainings.role = ?","Theoretical Instructor"] do def <<(theoretical_instructor) Training.send(:with_scope,create: { role: "Theoretical Instructor" }) { self.concat theoretical_instructor } end end accepts_nested_attributes_for :theoretical_instructors has_many :practical_instructors,"Practical Instructor"] do def <<(practical_instructor) Training.send(:with_scope,create: { role: "Practical Instructor" }) { self.concat practical_instructor } end end accepts_nested_attributes_for :practical_instructors end 这段代码让我可以做这样的事情 :001 > c = Course.first => #<Course id: 1> :002 > t1 = Trainer.first => #<Trainer id: 1,name: "Tom"> :003 > c.theoretical_instructors << t1 => #<Trainer id: 1,name: "Tom"> :004 > Training.all => [#<Training id: 1,role: "Theoretical Instructor",trainer_id: 1,course_id: 1>] 这是一个可接受的解决方法,即使在我的控制器中我仍然不能只做@course = Course.new(params [:course]),但我必须创建训练对象迭代params [:course] [:theoretical_instructor_ids]和params [:course] [:practical_instructor_ids]. 但我很好奇,所以问题仍然存在:为了使@course = Course.new(params [:course])能够与课程一起构建训练对象,我能做些什么? 现在……我想我在Rails中发现了一个错误: :005 > c.practical_instructors => [] # correct :006 > c.practical_instructor_ids => [] # obviously :007 > c.reload => #<Course id: 1> :008 > c.practical_instructor_ids => [1] # WRONG!!! :009 > c.practical_instructors => [] # now it's correct... :010 > c.practical_instructor_ids => [] # WTF!? 我想我会在github问题上报告这个…… 编辑3由oli-g Bug报道于github 解决方法
您的问题是,在创建记录之前,您将无法添加关联.在这种情况下,使用课程记录ID存储培训关联,并且直到首次保存课程之后才定义课程ID.您要做的是在创建记录后使用after_create回调来调用函数.
将其添加到课程模型的末尾: # Use attr accessors to store the initial values so they won't conflict with the *_instructor_ids methods defined above attr_accessor :create_theoretical_instructors attr_accessor :create_practical_instructors # This will call the create_training_records function after the record is created after_create :create_training_records private def create_training_records create_theoretical_instructors.each do |instructor_id| self.theoretical_instructors << Instructor.find(instructor_id) end create_practical_instructors.each do |instructor_id| self.practical_instructors << Instructor.find(instructor_id) end save! end 并在视图中更改表单以使用新的attr_accessors: <%= course_form.label :create_theoretical_instructors %><br /> <%= course_form.select :create_theoretical_instructors,{ multiple: true } %> <%= course_form.label :create_practical_instructors %><br /> <%= course_form.select :create_practical_instructors,{ multiple: true } %> 现在,当您提交表单时,它会将指导者ID写入新的Course实例变量;在课程经过验证和保存后,它将自动创建新的关联. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ruby – mongo db中的tailable游标超时
- ruby-on-rails – Rails4 ActionController :: InvalidAuth
- [Cocoa]_[初级]_[使用NSXMLElement 创建一个XML文件]
- ruby – EM :: Iterator的工作示例
- JSONKit使用中的注意事项
- StarUML类图相关——关联、聚合、组合、泛化、依赖、实现
- C++ 数据结构 堆排序的实现
- c# – 微软有没有使LINQ可以使用所有的集合?
- ruby-on-rails – (Rails)上传目录
- ruby – 如何优化ActiveRecord find_in_batches查询?