Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 一张表单上有多个记录_Ruby On Rails - Fatal编程技术网

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与“父”模型之间的关系是A
    parent有很多: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 -%>