Вложенные формы в Rails предоставляют мощный способ управления сложными отношениями между моделями. В этой статье блога мы углубимся в мир вложенных форм и рассмотрим различные методы их реализации в вашем приложении Rails. По ходу дела мы будем предоставлять примеры кода, которые помогут вам понять и эффективно реализовать эти методы.
- Использование метода
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 %>
- Использование
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 %>
- Использование
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)) %>');
});