Rails — fields_for и javascript для динамического добавления и удаления полей в форме (railscasts ep. 196-197)

ОБНОВЛЕНИЕ

Спасибо за ваш ответ.

Но если я удалю

for requested_role in @project.requested_roles

из частичного, то я не могу получить доступ к значению запрашиваемой_роли.роли, потому что у меня нет параметра X, полученного из кода

for X in @projects.requested_roles 

и я не могу написать X.role

Как я могу получить доступ к этому значению без использования for или .each для прокрутки запрашиваемых_ролей проекта?

ЗАВЕРШИТЬ ОБНОВЛЕНИЕ


У меня проблема с социальной сетью, которую я разрабатываю с помощью Ruby on Rails. Я следил за railscasts 196 и 197, чтобы создать форму с fields_for и динамически добавлять поля с помощью javascript, но у меня есть 2 основных проблемы.

Пользователь может создать проект, и этот проект должен иметь 1+ запрошенных_ролей. Когда я открываю страницу редактирования проекта для изменения ролей, если для проекта есть N запрашиваемых_ролей, я вижу N*N форм для изменения запрашиваемых_ролей. Итак, если у меня есть 2 запрашиваемых_роли (например, Режиссер и Продюсер), я вижу 4 поля выбора: Режиссер - Продюсер - Режиссер - Продюсер. Они повторяются N раз. И я не могу их изменить, потому что у меня может быть максимум 1 запрашиваемая_роль каждого типа. Хорошо, если у меня есть только 1 запрашиваемая_роль (потому что 1x1=1)

проект.рб

class Project < ActiveRecord::Base
attr_accessible :title, :requested_roles_attributes, :video, :num_followers, :num_likes

belongs_to :user

has_many :requested_roles, dependent: :destroy
accepts_nested_attributes_for :requested_roles, :reject_if => lambda { |a| a[:ruolo].blank? }, :allow_destroy => true

Запрошенная_роль.rb

class RequestedRole < ActiveRecord::Base
attr_accessible :role, :project_id 

belongs_to :project

Projects_controller.rb

class ProjectsController < ApplicationController

def new
  @project= Project.new
  @requested_role= @project.requested_roles.build    
end   

Проекты/edit.html.erb

<div class="row">
 <div class="span6 offset3">
  <%= form_for(@project) do |f| %>
    <%= render 'shared/error_messages', object: f.object%> 

    <%= f.label :title, "Project title" %>
    <%= f.text_field :title %>

    <%= f.fields_for :requested_roles do |builder| %>
          ciao
         <%= render 'requested_role', :f => builder   %>

    <% end %>

    <div class="fields">
    <p><%= link_to_add_fields "Add requested role", f, :requested_roles %></p>
    </div>

    </br>

    <%= f.submit 'Apply changes', class: 'btn btn-large btn-primary' %>

  <% end %>
</div>
</div>

Я думаю, что ошибка в этом представлении (Проекты/редактирование):

    <%= f.fields_for :requested_roles do |builder| %>
          ciao
         <%= render 'requested_role', :f => builder   %>
    <% end %>

этот код, даже без партиала, приводит к N-кратному повторению запрашиваемых_ролей. На самом деле без частичной _requested_role у нас N "чао", а должно быть только одно.

проекты/_requested_role.html.erb

<% if @project.requested_roles.any? %>
    <p>Modifica ruoli richiesti </p>
<%end%>
<%= @project.requested_roles.count %>
<% for requested_role in @project.requested_roles %>
    <div class="fields">

    <p>
    <p>Requested role: <%= role_to_string(requested_role.role) %></p>

    <%= f.label :role, "Modify role" %>
    <%= f.select :role, options_for_select([["Regista",1],["Sceneggiatore", 2],["Direttore della fotografia", 3], ["Operatore",4],
                                      ["Fonico", 5], ["Montatore", 6], ["Truccatrice",7], ["Costumista",8], ["VFX Artist",9],
                                      ["Produttore", 10], ["Attore",11], ["Attrice",12], ["Grip/Runner",13]], :selected => requested_role.role) %>


    <%= link_to_remove_fields "remove", f %>    #dinamically remove a field
    </p>

<% end %>

</div>

Не могли бы вы мне помочь? Не могу понять где ошибка. Заранее спасибо.

Другая проблема связана со ссылками для динамического удаления и добавления запрашиваемых_ролей (javascript-jquery).

Если у меня есть 3 запрашиваемых_роли (9 полей выбора вместо 3 из-за ошибки, о которой я упоминал ранее) и я удаляю (через link_to_remove_fields) последнее, проблем нет. Но если я удалю первый, поля и даже кнопка отправки под ним исчезнут, и я не смогу изменить роли или отправить изменения.

Когда я добавляю (через link_to_add_fields) новую роль и у меня уже есть, например, 2 запрашиваемых_роли (Режиссер, Продюсер), при переходе по ссылке для добавления новой запрашиваемой_роли возникает еще одна ошибка. Вместо поля выбора для выбора роли появляется копия 2-х существующих полей выбора (Режиссер, Продюсер).

application_helper.rb

def link_to_remove_fields(name, f)
  f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)")
end


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

Application.js

function remove_fields(link) {
    $(link).prev("input[type=hidden]").val("1");
    $(link).closest(".fields").hide();
}


function add_fields(link, association, content) {
    var new_id = new Date().getTime();
    var regexp = new RegExp("new_" + association, "g")
    $(link).parent().before(content.replace(regexp, new_id));
}

Я не могу понять, что пошло не так. Если у вас есть идея, можете ли вы дать мне несколько советов? Большое Вам спасибо.

Дарио


person Dario Carbone    schedule 31.08.2014    source источник


Ответы (1)


Проблема в том, что вы повторяете дважды.

<%= f.fields_for :requested_roles do |builder| %>
  ciao
  <%= render 'requested_role', :f => builder   %>
<% end %>

Будет автоматически повторяться партиал requested_role для каждой запрошенной роли. Вот почему он показывает «чао» N раз, потому что это то, что делает fields_for при рендеринге. Вероятно, вам нужно прочитать документ, чтобы понять, как это работает: http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for

Так что нет необходимости иметь

for requested_role in @project.requested_roles

в вашем частичном. Он будет повторять все запрошенные роли только каждый раз, когда fields_for отрисовывает их. Вот как должен выглядеть ваш код в вашем edit.html.erb :

<% if @project.requested_roles.any? %>
  <p>Modifica ruoli richiesti </p>
<%end%>

<%= @project.requested_roles.count %>

<%= f.fields_for :requested_roles do |builder| %>
   <%= render 'requested_role', :f => builder   %>
<% end %>

<p><%= link_to_add_fields "Add requested role", f, :requested_roles %></p>

А партиал requested_role должен быть просто:

<div class="fields">
  <div>
    <p>Requested role: <%= role_to_string(f.object.role) %></p>

    <%= f.label :role, "Modify role" %>
    <%= f.select :role, options_for_select([["Regista",1],["Sceneggiatore", 2],["Direttore della fotografia", 3], ["Operatore",4],
                                  ["Fonico", 5], ["Montatore", 6], ["Truccatrice",7], ["Costumista",8], ["VFX Artist",9],
                                  ["Produttore", 10], ["Attore",11], ["Attrice",12], ["Grip/Runner",13]], :selected => f.object.role) %>


    <%= link_to_remove_fields "remove", f %>
  </div>
</div>

Исправление вашего частичного должно решить вашу вторую проблему со ссылками.

Возможно, вы захотите использовать драгоценный камень Райана для nested_forms

https://github.com/ryanb/nested_form

person Marc Lainez    schedule 31.08.2014
comment
Рад это слышать. Если бы мой ответ был действительно правильным, было бы неплохо проголосовать за него или принять его;) - person Marc Lainez; 22.09.2014
comment
Я не могу голосовать из-за низкой репутации, но я принял это. ;) - person Dario Carbone; 30.09.2014