Поля для вложенных атрибутов внутри цикла в форме рельсов - PullRequest
0 голосов
/ 28 мая 2018

Я пытался сделать что-то вроде Google Business, где у вас есть дни недели, и вы можете добавить к нему несколько раз.Я следую форме вложенной модели рельса , но мне не удалось заставить ее работать так, как я хотел бы.

Я хочу иметь местоположение с 7 дняминеделю, и вы можете добавить несколько раз в каждый день.Кажется, что метод create работает должным образом, поскольку форма существует с нуля.Затем, когда я иду в редактирование, каждый день имеет все время, которые были сохранены при создании.

Я просто хотел бы получить некоторые рекомендации в этом вопросе.Спасибо!

_from.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 %>

_time_fields.html.erb

<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

Модели

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

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

РЕДАКТИРОВАТЬ

Попробовав разные вещи, я получил желаемый результат.Однако не уверен, что это лучший способ сделать это.

application_helper.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

location_controller.rb

def new
  @location = Location.new
end

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

_time_fields.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>

_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>
    <!-- add button -->
    <div class="col-md-3">
      <%= link_to_add_fields "Add Time", "btn", "repeater-add", "time#{idx}",  form, :times, idx %>
    </div>
  </div>
<% end %>

js

function remove_fields(link) {
  $(link).prev("input[type=hidden]").val("true");
  $(link).closest(".weekday-time").hide();
}

function add_fields(link, association, content) {
  let _attr = $(link).attr('data_attr');
  var new_id = new Date().getTime();
  var regexp = new RegExp("new_" + association, "g");
  $(content.replace(regexp, new_id)).insertAfter($("#" + _attr));
}

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Я думаю, что мог бы быть другой способ сделать это.Если это так, пожалуйста, не стесняйтесь указать это и ответить на этот вопрос.Однако, если кто-то ищет решение с похожей проблемой, это то, что я сделал.

Я перебираю дни недели, а затем на create, _current_time возвращает true, чтоможет использоваться как аргумент record_object для fields_for.Это займет 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 вызывал проблему, поэтому я отправляю только эту часть в качестве ответа.

0 голосов
/ 28 мая 2018

Предоставление базового решения здесь.Вам может понадобиться его рефакторинг.

Мы создаем семь экземпляров Location.Каждый на будний день.Хотя я не добавил 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

location.rb

class Location < ApplicationRecord
  has_many :timings
  accepts_nested_attributes_for :timings
end

Объяснение создания нескольких записей можно найти здесь .

Я не добавил link_to_add_fields вариант под формой.Вы можете сослаться на эпизод Railscast , который вы упомянули в вопросе, или использовать что-то вроде cocoon

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...