Ruby on rails 一张表单上有多个记录
我想创建一个具有以下格式的表单:Ruby on rails 一张表单上有多个记录,ruby-on-rails,Ruby On Rails,我想创建一个具有以下格式的表单: Shared Fields Fields Unique to record A [add another record button] 可根据需要多次单击[添加]按钮以创建 Shared Fields Fields Unique to record A Fields Unique to record B Fields Unique to record C [add another record button] 提交表单将创建记录A、B和C 后端 这将创建3条
Shared Fields
Fields Unique to record A
[add another record button]
可根据需要多次单击[添加]按钮以创建
Shared Fields
Fields Unique to record A
Fields Unique to record B
Fields Unique to record C
[add another record button]
提交表单将创建记录A、B和C
后端
这将创建3条记录,每个记录都具有与表单中的字段相同的共享和唯一属性
更新
有一点是大家共享的,那就是他们每个人都属于一个“雇主”。这应该是@employer的表格
大声想想,我们可以将共享属性作为属性访问器保存在父级上,并在子级控制器的“child#create”操作中将它们分配给子级。因为您在一个表单中填充多个模型而不嵌套,所以您不能只为@something生成带有
表单的表单,因为你没有一个对象可以填充
我会检查数据库结构,看看是否有办法将共享字段提取到单独的模型中。但如果没有办法做到干净,请继续阅读
用于呈现对象表单的Rails帮助程序以Rails可以正确解析为散列的方式布置字段。这反过来又可以用来构造一个对象。通过使用以下命令:
form_for @thing do |f|
t.text_field :name
end
您将得到一个带有thing[name]
字段的表单,它将在params
中查找,如下所示:
{..., thing: {name: "Hello world"}, ...}
有关此操作的更多详细信息,请参阅
现在的问题是:你没有一个对象可以填充。但您可以忽略这一点,构建一个仍然会被解析为嵌套哈希的表单。您只需手动填写Rails可能猜到的内容:表单URL和对象名
form_for :thing, url: thing_path do |f|
f.text_field :name
end
如果要创建一组字段,请在此表单中为
helper使用fields\u。更多信息,形式如下:
form_for :thing, url: thing_url do |f|
f.text_field :name
f.fields_for :something do |s|
s.text_field :value
end
end
这将呈现一个字段集,该字段集将被解析为单个散列。但是在您的案例中可能需要一个嵌套字段集数组,因此请参阅文档
最终你会得到:
- 散列
- 共享参数
- 对象数组
- 对象A
- 对象A
- 对象B
现在最大的问题是——您需要通过JavaScript向表单中添加字段,但它应该提前知道要添加什么标记。有很多方法可以解决这个问题,其中之一是为每个独特的模型呈现一个示例表单,并使用JavaScript对其进行采样
Edit:巧合的是,我需要找到如何呈现一个“裸”(没有对象支持)表单,该表单可以被JavaScript复制,并且在给定多个表单时看起来像参数中的对象数组
棘手的部分是,如果您为某个对象使用字段,它将为单个对象生成一个表单,而不是它们的数组。翻阅之后,我发现了一个似乎没有文档的特性(翻阅源代码)。它的用法如下(为了简洁起见,我使用HAML/Slim语法):
有趣的是,您可以只克隆resultig字段集而不修改它,Rails(甚至Rack?)将把这组表单解析为一个单独的对象。这依赖于浏览器保持字段的顺序,这在大多数情况下都是正确的。在新的.html.erb中
<div id="formDiv">
<%= form_for @user do |f| %>
<%= render 'shared/error_messages' %><br>
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<%= f.label :email %><br>
<%= f.email_field :email %><br>
<%= f.label :password %><br>
<%= f.password_field :password %><br>
<%= f.label :password_confirmation, "Confirmation" %><br>
<%= f.password_field :password_confirmation %><br>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
<input id="add" type="submit" value="Add"/>
</div>
<script>
$("#add").click(function() {
$.ajax({
url: "newAjax",
success: function (html) {
$("#formDiv").append(html);
}
});
});
$('form').submit(function(){
$('.multiform').each(function() {
$(this).submit();
});
return true;
});
</script>
我们希望确保我们的布局没有使用AJAX表单呈现,这样我们就不会重新加载JS/CSS文件等。这是我最后使用的工作代码。谢谢所有帮助过我的人。遵循D-side的方法,但使用“雇主”作为基础模型。我可能会对其进行重构以删除雇主上的attr_访问器,并在视图中使用字段标记。最后,我只是从传递给控制器的“params”数组中提取共享值
订票控制员:
def new
@employer = current_employer
@booking = @employer.bookings.build
respond_with(@booking)
end
def create
errors = []
booking_create_params["new_booking_attributes"].each do |booking|
new_booking = current_employer.bookings.build(booking)
new_booking.job_type_id = booking_create_params["job_type_id"]
new_booking.vehicle_id = booking_create_params["vehicle_id"]
new_booking.location_id = booking_create_params["location_id"]
new_booking.pay = booking_create_params["pay"]
unless new_booking.save
errors << new_booking.errors.full_messages
end
end
if errors == []
flash[:notice] = "Bookings posted!"
redirect_to new_booking_path
else
flash[:notice] = "Error: #{errors.join(', ')}!"
redirect_to new_booking_path
end
end
def新建
@雇主=当前雇主
@预订=@employer.bookings.build
用(@booking)回复您
结束
def创建
错误=[]
预订\创建\参数[“新预订\属性”]。每个都要预订|
新预订=当前雇主。预订。构建(预订)
new_booking.job_type_id=booking_create_params[“job_type_id”]
new_booking.vehicle_id=预订_创建_参数[“vehicle_id”]
new_booking.location_id=预订_创建_参数[“location_id”]
new_booking.pay=预订_创建_参数[“pay”]
除非有新的预订
错误
位置:
转移
其中部分内容是:
<li class="close-list-item">
<!-- Recommended: post at least 1 week in advance
& shift length at least 4 hours.
-->
<% new_or_existing = booking.new_record? ? 'new' : 'existing' %>
<% prefix = "employer[#{new_or_existing}_booking_attributes][]" %>
<%= fields_for prefix, booking do |booking_form| -%>
<div class="shifts">
<div class="form-group shift">
<div class="row">
<div class="col-sm-4">
<label for="">Date</label>
<i class="glyphicon glyphicon-time"></i>
<%= booking_form.text_field :start, class: 'form-control booking-date', placeholder: 'Date', data: { provide: "datepicker", date_clear_btn: "true", date_autoclose: "true", date_start_date: '+1d', date_format: "yyyy-mm-dd" } %>
</div>
<div class="col-sm-4">
<label>Time Start</label><br>
<%= booking_form.select(:start_time, options_for_select(
booking_times_array
), { include_blank: true }, { class: 'form-control booking-time booking-time-start' } ) %>
</div>
<div class="col-sm-4">
<label>
Time End
</label>
<%= link_to "javascript:;", class: 'pull-right remove-shift' do %>
<i class="glyphicon glyphicon-remove"></i>
<% end %>
<script type="text/javascript">
$(".remove-shift").click(function(){
$(this).parents("li").remove();
});
</script>
<%= booking_form.select(:end_time, options_for_select(
booking_times_array
), { include_blank: true }, { class: 'form-control booking-time booking-time-end' } ) %>
</div>
</div>
</div>
</div>
</li>
<% end -%>
日期
开始时间
时间结束
$(“.remove shift”)。单击(函数(){
$(this.parents(“li”).remove();
});
您已经描述了前端,那么后端呢?实际应该填写哪些数据?更新了描述我对你的术语有点困惑。当你说“模型”时,你是指“模型类的记录/实例”吗?对不起,是的!我将在您的示例中更新,A、B和C与“父”模型之间的关系是Aparent有很多:A
家长有很多:b
,家长有很多:c
,每个A、b和c都属于:家长
,对吗?不客气!顺便说一下,我用最近的发现更新了我的答案。我一直在想为什么D
<%= form_for @user, remote: true, html: { class: 'multiForm' } do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<%= f.label :email %><br>
<%= f.email_field :email %><br>
<%= f.label :password %><br>
<%= f.password_field :password %><br>
<%= f.label :password_confirmation, "Confirmation" %><br>
<%= f.password_field :password_confirmation %><br>
<% end %>
def newAjax
@user = User.new
render :layout => false
end
def new
@employer = current_employer
@booking = @employer.bookings.build
respond_with(@booking)
end
def create
errors = []
booking_create_params["new_booking_attributes"].each do |booking|
new_booking = current_employer.bookings.build(booking)
new_booking.job_type_id = booking_create_params["job_type_id"]
new_booking.vehicle_id = booking_create_params["vehicle_id"]
new_booking.location_id = booking_create_params["location_id"]
new_booking.pay = booking_create_params["pay"]
unless new_booking.save
errors << new_booking.errors.full_messages
end
end
if errors == []
flash[:notice] = "Bookings posted!"
redirect_to new_booking_path
else
flash[:notice] = "Error: #{errors.join(', ')}!"
redirect_to new_booking_path
end
end
<div id="bookings">
<ol class="numbers">
<li>
<legend>Location, Pay, & Vehicle</legend>
<div class="form-group">
<div class="row">
<div class="col-sm-6">
<label>Type of job</label><br>
<%= f.select(:job_type_id, options_from_collection_for_select(JobType.all, :id, :name_with_delivery), {}, { id: 'job-type', class: 'form-control' }) %>
</div>
<div class="col-sm-6">
<label>Vehicle needed</label><br>
<%= f.select(:vehicle_id, options_from_collection_for_select(Vehicle.all, :id, :name), {}, { id: 'vehicle-type', class: 'form-control' }) %>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6">
<label>Location</label>
<% if current_employer.locations.count > 1 %>
<%= f.select :location_id, options_from_collection_for_select(current_employer.locations.all, :id, :name_or_address_1), {}, { class: 'form-control' } %>
<% elsif current_employer.locations.count == 1 %>
<p><strong>Location: </strong><%= current_employer.locations.first.name_or_address_1 %></p>
<%= f.hidden_field :location_id, current_employer.locations.first.id %>
<% end %>
<%= link_to "or add new location", new_employer_location_path(current_employer, Location.new) %>
</div>
<div class="col-sm-6">
<%= f.label :pay %><br>
<%= f.text_field :pay, class: 'form-control' %>
</div>
</div>
</div>
</li>
<legend>Shifts</legend>
<%= render 'booking', booking: Booking.new %>
</ol>
</div>
<li class="close-list-item">
<!-- Recommended: post at least 1 week in advance
& shift length at least 4 hours.
-->
<% new_or_existing = booking.new_record? ? 'new' : 'existing' %>
<% prefix = "employer[#{new_or_existing}_booking_attributes][]" %>
<%= fields_for prefix, booking do |booking_form| -%>
<div class="shifts">
<div class="form-group shift">
<div class="row">
<div class="col-sm-4">
<label for="">Date</label>
<i class="glyphicon glyphicon-time"></i>
<%= booking_form.text_field :start, class: 'form-control booking-date', placeholder: 'Date', data: { provide: "datepicker", date_clear_btn: "true", date_autoclose: "true", date_start_date: '+1d', date_format: "yyyy-mm-dd" } %>
</div>
<div class="col-sm-4">
<label>Time Start</label><br>
<%= booking_form.select(:start_time, options_for_select(
booking_times_array
), { include_blank: true }, { class: 'form-control booking-time booking-time-start' } ) %>
</div>
<div class="col-sm-4">
<label>
Time End
</label>
<%= link_to "javascript:;", class: 'pull-right remove-shift' do %>
<i class="glyphicon glyphicon-remove"></i>
<% end %>
<script type="text/javascript">
$(".remove-shift").click(function(){
$(this).parents("li").remove();
});
</script>
<%= booking_form.select(:end_time, options_for_select(
booking_times_array
), { include_blank: true }, { class: 'form-control booking-time booking-time-end' } ) %>
</div>
</div>
</div>
</div>
</li>
<% end -%>