以rails形式循环内嵌套属性的字段

时间:2018-05-28 14:42:48

标签: ruby-on-rails ruby ruby-on-rails-5

我尝试做谷歌我的业务,​​你有一周的日子,你可以添加多次。我遵循rail cast nested model form,但我无法按照我想要的方式工作。

我想拥有一周中7天的位置,您可以每天添加多次。 Create方法似乎按预期工作,因为表单是从头开始的。然后当我进入编辑时,每天都有创建时保存的所有时间。

我想在这个问题上提供一些指导。谢谢!

_from.html.erb

procedure Calculate;
begin
  // this is my calculation procedure
  ShowMessage('calculation running correctly'); 
end;

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
var
N   : integer;
begin
  if Key = #13 then
  begin
    N := StrtoInt(Edit1.Text);
    if N<10 then ShowMessage('<10!') else
      if N>100 then ShowMessage('>100!') else Calculate;
  end;
end;

_time_fields.html.erb

<% (0..6).each do |idx| %>
  <div class="row">
    <div class="col-md-2">
      <p><% I18n.t('date.day_names')[idx] %></p>
    </div>
    <div class="col-md-5">
      <%= form.fields_for :times do |f| %>
        <%= render "time_fields", :form => f %>
      <% end %>
    </div>
    <div class="col-md-3">
      <%= link_to_add_fields "Add Time", "btn", "repeater-add",  form, :times %>
    </div>
  </div>
<% end %>

控制器

<div class="weekday-time" id="time">
  <%= form.hidden_field :weekday_id, value: form.options[:child_index] %>
  <div class="col-md-9">
    <div class="input-group bootstrap-timepicker timepicker">
      <%= form.text_field :time, id: "timepicker" %>
      <span class="input-group-addon"><i class="glyphicon glyphicon-time"></i></span>
    </div>
    <div class="col-md-3">
      <%= link_to_remove_fields "Delete Time, "btn", "repeater-remove", form %>
    </div>
  </div>
</div>

模型

def new
  @location = Location.new
  @location.times.build
end

修改

在尝试不同的事情后,我得到了我想要的结果。但是,不确定这是否是最好的方法。

application_helper.rb

class Time < ApplicationRecord
  belongs_to :location, optional: true
end

class Location < ApplicationRecord
  has_many :times, dependent: :destroy
  accepts_nested_attributes_for :times
end

location_controller.rb

module ApplicationHelper
  def link_to_remove_fields(name, html_class, data_attr, html_id, form)
    form.hidden_field(:_destroy) + link_to_function(name, html_class, html_id, data_attr, "remove_fields(this)")
  end

  def link_to_add_fields(name, html_class, html_id, data_attr, form, association, idx)
    new_object = form.object.class.reflect_on_association(association).klass.new
    fields = form.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
      render(association.to_s.singularize + "_fields", :form => builder, idx: idx)
    end
    link_to_function(name, html_class, html_id, data_attr, "add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")")
  end

  def link_to_function(name, html_class, html_id, data_attr, *args, &block)
     html_options = args.extract_options!.symbolize_keys

     function = block_given? ? update_page(&block) : args[0] || ''
     onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
     href = html_options[:href] || '#'

     content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick, :class => html_class, :id => html_id, :data_attr => data_attr))
  end  
end

_time_fields.html.erb

def new
  @location = Location.new
end

def edit
  @times = Times.where(location_id: @location.id)
end

_form.html.erb

<div class="weekday-time" id="time">
  <%= form.hidden_field :weekday_id, value: idx %>
  <div class="col-md-9">
    <div class="input-group bootstrap-timepicker timepicker">
      <%= form.text_field :time, id: "timepicker" %>
      <span class="input-group-addon"><i class="glyphicon glyphicon-time"></i></span>
    </div>
  </div>
  <div class="col-md-3">
    <%= link_to_remove_fields "Delete Time, "btn", "plahecolder", "repeater-remove", form %>
  </div>
</div>

JS

<% (0..6).each do |idx| %>
  <div class="row">
    <div class="col-md-2">
      <p><%= I18n.t('date.day_names')[idx] %></p>
    </div>
    <div class="col-md-5">
      <div id="time<%= idx %>">
        <% _current_time = @location.new_record? ? @location.times.build : @times.where(location_id: idx) %>
        <% unless _current_time.blank? %>
          <%= form.fields_for :times, _current_time do |f| %>
            <%= render "time_fields", :form => f, :idx => idx %>
          <% end %>
        <% end %>
        </div>
    </div>
    <!-- add button -->
    <div class="col-md-3">
      <%= link_to_add_fields "Add Time", "btn", "repeater-add", "time#{idx}",  form, :times, idx %>
    </div>
  </div>
<% end %>

2 个答案:

答案 0 :(得分:1)

我认为可能还有另一种方法可以做到这一点。如果是这样,请毫不犹豫地指出并回答这个问题。但是,如果有人正在寻找具有类似问题的解决方案,那就是我所做的。

我遍历一周中的几天,然后在create上,_current_time将返回true,这可以用作fields_for的record_object参数。它需要record_object,但我create没有,所以true就足够了(不确定100%为什么)。然后在update上,我遍历一周中某一天的时间并跳过创建没有的字段。

_form.html.erb

<% (0..6).each do |idx| %>
  <div class="row">
    <div class="col-md-2">
      <p><%= I18n.t('date.day_names')[idx] %></p>
    </div>
    <div class="col-md-5">
      <div id="time<%= idx %>">
        <% _current_time = @location.new_record? ? @location.times.build : @times.where(location_id: idx) %>
        <% unless _current_time.blank? %>
          <%= form.fields_for :times, _current_time do |f| %>
            <%= render "time_fields", :form => f, :idx => idx %>
          <% end %>
        <% end %>
        </div>
    </div>
    <div class="col-md-3">
      <%= link_to_add_fields "Add Time", "btn", "repeater-add", "time#{idx}",  form, :times, idx %>
    </div>
  </div>
<% end %>

添加按钮将在任一种情况下使用适当的索引创建新的时间。在这个问题的编辑部分,您可以看到完整的实现。只有_form.html.erb导致了这个问题,所以我只是张贴这篇文章作为答案。

答案 1 :(得分:0)

在此提供基本解决方案。你可能需要重构它。

我们正在创建七个位置实例。每个工作日。虽然我的解决方案中没有添加thisSymbolValue列。我相信你可以照顾它。

然后在this方法下,我们使用weekday_id方法获取每个参数并将其列入白名单,然后创建记录。

create

locations_params

_form.html.erb

<%= form_tag locations_path do |main_form| %>
  <% @locations.each do |location| %>
    <%= fields_for 'locations[]', location do |f| %>
      <%= f.label :name %>
      <%= f.text_field :name %> <br>
      <%= f.fields_for :timings, f.object.timings.build do |timing_form| %>
        <%= timing_form.label :start_time %>
        <%= timing_form.text_field :start_time, type: "time" %> <br>
      <% end %>
    <% end %>
  <% end %>
  <%= submit_tag %>
<% end %>

locations_controller.rb

class LocationsController < ApplicationController
  def new
    @locations = []
    7.times do
      @locations << Location.new
    end
  end

  def create
    params[:locations].each do |location|
      Location.create!(locations_params(location))
    end
    redirect_to root_path
  end

  private

  def locations_params(my_params)
    my_params.permit(:name, :timings_attributes => [:start_time, :id, :_destroy, :locatino_id])
  end
end

可以找到创建多条记录的说明here

我没有在表单下添加location.rb选项。您可以参考问题中提到的Railscast episode或使用cocoon

之类的内容