当我单击“删除学生”时,它会删除该链接上方的每个字段
这是您所关注的特定 RailsCast 的一个众所周知的问题(它已过时)。还有另一个here https://www.youtube.com/watch?v=-WJUaCI-SWg:
问题归结为child_index https://www.youtube.com/watch?v=-WJUaCI-SWg of the fields_for参考 https://stackoverflow.com/questions/2879208/rails-fields-for-child-index-option-explanation.
每次使用时fields_for
(这就是您使用上述 javascript 功能复制的内容),它分配一个id
它创建的每组字段。这些ids
用于params
分离不同的属性;它们也被分配到每个字段作为HTML“id”属性 http://www.w3schools.com/jsref/prop_html_id.asp.
因此,您遇到的问题是,由于您没有更新此内容child_index
每次添加新字段时,它们都是相同的。自从你的link_to_add_fields
helper 不会更新 JS(IE 允许您附加具有完全相同的字段child_index
),这意味着每当您“删除”一个字段时,它都会选择所有字段。
解决此问题的方法是设置child_index
(下面我会给你解释)。
老实说,我宁愿给你新的代码,也不愿挑选过时的东西。
我在这里写过这一点(尽管可以稍微修改一下):Rails Accepts_nested_attributes_for 与 f.fields_for 和 AJAX https://stackoverflow.com/questions/20436526/rails-accepts-nested-attributes-for-with-f-fields-for-and-ajax
有一些宝石可以为你做到这一点 - 一种叫做Cocoon https://github.com/nathanvda/cocoon非常受欢迎,尽管许多人认为它不是“即插即用”解决方案。
尽管如此,最好知道这一切都有效,即使您确实选择使用类似的东西Cocoon
...
字段_for http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
要理解该解决方案,您必须记住 Rails 创建HTML forms.
你可能知道这一点;很多人没有。
这很重要,因为当你意识到这一点时HTML表格必须遵守以下规定所施加的所有限制HTML,您就会明白 Rails 并不是很多人想象的魔术师。
创建“嵌套”表单的方法(without添加/删除)功能如下:
#app/models/student.rb
class Student < ActiveRecord::Base
has_many :teachers
accepts_nested_attributes_for :teachers #-> this is to PASS data, not receive
end
#app/models/teacher.rb
class Teacher < ActiveRecord::Base
belongs_to :student
end
需要注意的重要一点是,您的accepts_nested_attributes_for http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html应该在parent模型。也就是说,您将数据传递到的模型(而不是接收数据的模型):
嵌套属性允许您在关联记录上保存属性
通过父母
#app/controllers/students_controller.rb
class StudentsController < ApplicationController
def new
@student = Student.new
@student.teachers.build #-> you have to build the associative object
end
def create
@student = Student.new student_params
@student.save
end
private
def student_params
params.require(:student).permit(:x, :y, teachers_attributes: [:z])
end
end
有了这些物体built,您可以在表单中使用它们:
#app/views/students/new.html.erb
<%= form_for @student do |f| %>
<%= f.fields_for :teachers |teacher| %>
<% # this will replicate for as many times as you've "built" a new teacher object %>
<%= teacher.text_field ... %>
<% end %>
<%= f.submit %>
<% end %>
这是一个标准表单,它将数据发送到您的控制器,然后发送到您的模型。这accepts_nested_attributes_for
模型中的方法会将嵌套属性传递给依赖模型。
--
对此最好的做法是注意id
对于上面代码创建的嵌套字段。我手头没有任何例子;它应该显示嵌套字段的名称如下teachers_attributes[0][name]
etc.
需要注意的重要一点是[0]
- 这是子索引这在您需要的功能中起着至关重要的作用。
Dynamic
现在是动态形式。
第一部分相对简单...removing字段是从 DOM 中删除它的情况。我们可以使用child_index
为此,所以我们首先需要知道如何设置子索引等等等等......
#app/models/Student.rb
class Student < ActiveRecord::Base
def self.build #-> non essential; only used to free up controller code
student = self.new
student.teachers.build
student
end
end
#app/controllers/students_controller.rb
class StudentsController < ApplicationController
def new
@student = Student.build
end
def add_teacher
@student = Student.build
render "add_teacher", layout: false
end
def create
@student = Student.new student_params
@student.save
end
private
def student_params
params.require(:student).permit(:x, :y, teachers_attributes: [:z])
end
end
现在的视图(请注意,您必须将表单拆分为部分视图):
#app/views/students/new.html.erb
<%= form_for @student do |f| %>
<%= f.text_field :name %>
<%= render "teacher_fields", locals: {f: f} %>
<%= link_to "Add", "#", id: :add_teacher %>
<%= f.submit %>
<% end %>
#app/views/_teacher_fields.html.erb
<%= f.fields_for :teachers, child_index: Time.now.to_i do |teacher| %>
<%= teacher.text_field ....... %>
<%= link_to "Remove", "#", id: :remove_teacher, data: {i: child_index} %>
<% end %>
#app/views/add_teacher.html.erb
<%= form_for @student, authenticity_token: false do |f| %>
<%= render partial "teacher_fields", locals: {f:f}
<% end %>
This should为您呈现各种表格等,包括fields_for
。注意child_index: Time.now.to_i
-- 这为每个设置一个唯一的 IDfields_for
,使我们能够根据您的需要区分每个字段。
做这个dynamic然后归结为JS:
#config/routes.rb
resources :students do
get :add_teacher, on: :collection #-> url.com/students/get_teacher
end
使用此路由允许我们发送 Ajax 请求(以获取新字段):
#app/assets/javascripts/.....coffee
$ ->
#Add Teacher
$(document).on "click", "#add_teacher", (e) ->
e.preventDefault();
#Ajax
$.ajax
url: '/students/add_teacher'
success: (data) ->
el_to_add = $(data).html()
$('#subscribers').append(el_to_add)
error: (data) ->
alert "Sorry, There Was An Error!"
#Remove Teacher
$(document).on "click", "#remove_teacher", (e) ->
e.preventDefault();
id = $(this).data("i")
$("input#" + i).remove()