Изучение вложенных форм в Rails: подробное руководство

Вложенные формы в Rails предоставляют мощный способ управления сложными отношениями между моделями. В этой статье блога мы углубимся в мир вложенных форм и рассмотрим различные методы их реализации в вашем приложении Rails. По ходу дела мы будем предоставлять примеры кода, которые помогут вам понять и эффективно реализовать эти методы.

  1. Использование метода fields_for.
    Метод fields_forпозволяет создавать вложенные поля формы внутри родительской формы. Обычно он используется, когда между моделями имеется связь «один-ко-многим» или «многие-ко-многим». Вот пример:
# app/models/user.rb
class User < ApplicationRecord
  has_many :posts
  accepts_nested_attributes_for :posts
end
# app/views/users/_form.html.erb
<%= form_for @user do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>

  <%= f.fields_for :posts do |p| %>
    <%= p.label :title %>
    <%= p.text_field :title %>
  <% end %>

  <%= f.submit %>
<% end %>
  1. Использование nested_attributes_for:
    Метод nested_attributes_forпозволяет сохранять связанные записи с помощью родительской модели. Он автоматически создает связанные записи и предоставляет методы для их создания, обновления или уничтожения. Вот пример:
# app/models/user.rb
class User < ApplicationRecord
  has_many :posts
  accepts_nested_attributes_for :posts
end
# app/controllers/users_controller.rb
def new
  @user = User.new
  @user.posts.build
end
def user_params
  params.require(:user).permit(:name, posts_attributes: [:id, :title, :_destroy])
end
# app/views/users/_form.html.erb
<%= form_for @user do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>

  <%= f.fields_for :posts do |p| %>
    <%= p.label :title %>
    <%= p.text_field :title %>
    <%= p.check_box :_destroy %>
  <% end %>

  <%= f.submit %>
<% end %>
  1. Использование accepts_nested_attributes_forс fields_forи link_to_add_fields:
    Этот метод позволяет динамически добавлять или удалять вложенные поля формы с помощью JavaScript. Вот пример:
# app/models/user.rb
class User < ApplicationRecord
  has_many :posts
  accepts_nested_attributes_for :posts
end
# app/views/users/_form.html.erb
<%= form_for @user do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>

  <div id="posts">
    <%= f.fields_for :posts do |p| %>
      <%= render 'post_fields', f: p %>
    <% end %>
  </div>

  <%= link_to_add_fields 'Add Post', f, :posts %>

  <%= f.submit %>
<% end %>
# app/views/users/_post_fields.html.erb
<div class="nested-fields">
  <%= f.label :title %>
  <%= f.text_field :title %>
  <%= link_to_remove_fields 'Remove', f %>
</div>
# app/assets/javascripts/application.js
function remove_fields(link) {
  $(link).previous("input[type=hidden]").value = "1";
  $(link).up(".nested-fields").hide();
}
function add_fields(link, association, content) {
  var new_id = new Date().getTime();
  var regexp = new RegExp("new_" + association, "g");
  $(link).up().insert({
    before: content.replace(regexp, new_id)
  });
}
$('form').on('click', '.remove_fields', function(event) {
  event.preventDefault();
  remove_fields(this);
});
$('form').on('click', '.add_fields', function(event) {
  event.preventDefault();
  add_fields(this, 'posts', '<%= escape_javascript(render("post_fields", f: f)) %>');
});