#ruby-on-rails #ruby
#ruby-on-rails #ruby
Вопрос:
Является ли метод colleciton.build разрушительным?
например (я ссылался https://api.rubyonrails.org/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-build )
class Pet
belongs_to :person
end
class Person
has_many :pets
end
new_pet = person.pets.build
# => #<Pet id: nil, name: nil, person_id: 1>
new_pet
# => #<Pet id: nil, name: nil, person_id: 1>
Я могу это понять.
Но,
person.pets
# => [#<Pet id: nil, name: nil, person_id: 1>]
человек.домашние животные выглядят разрушительными из-за метода сборки коллекции.
Я думаю person.pets
, что возвращает пустую коллекцию.
Я не могу понять это поведение. Почему это так? Документы пишут о методе сборки, как показано ниже
Возвращает новый объект типа коллекции, который был создан с атрибутами и связан с этим объектом, но еще не был сохранен. Вы можете передать массив хэшей атрибутов, это вернет массив с новыми объектами.
Комментарии:
1. Что именно вы подразумеваете под деструктивным ? Я полагаю, вы думаете, что он переопределяет текущий
person.pets
. Вы проверяли это, проверяя значениеperson.pets
перед вызовомperson.pets.build
, а затем проверяя значениеperson.pets
впоследствии?build
не следует уничтожать какие-либо данные, он должен возвращать новый экземпляр и добавлять вновь созданный экземпляр в связанную коллекцию.2. @3limin4t0r: возможно, они имели в виду это как «мутирующее»
3. @SergioTulentsev Это то, о чем я тоже подумал, поэтому я попросил разъяснений.
4. @3limin4t0r Спасибо за комментарии. «деструктивный» означает изменение.
Ответ №1:
Да, он «деструктивный» в том смысле, что он изменяет коллекцию, добавляя новый элемент.
Я не могу понять это поведение. Почему это так?
Я уверен, что есть много причин, но очевидная, которая приходит на ум, — это упрощает клиентский код. Предположим, у вас есть человек, у которого уже есть несколько домашних животных, и вы хотите предоставить пользователю возможность добавлять новых домашних животных.
# controller
@person = Person.find(params[:id])
@person.pets.size # => 2
@person.pets.build
# view
<% @person.pets.each do |pet| %>
<% if pet.persisted? %>
display pet
<% else %>
render new pet form
<% end %>
<% end %>
Вы могли бы сделать что-то подобное @new_pet = Pet.new(person_id: @person.id)
и использовать это для рендеринга формы, но это выглядит более сложным. Кроме того, описанный выше подход позволяет добавлять новые элементы по N за раз: просто создайте N новых питомцев перед рендерингом страницы.
Комментарии:
1. Спасибо за ответ. Я стал способен понять это поведение. И я впервые знаю, что «деструктивный» в ja означает «мутирующий» в en. Я многому научился у вас
Ответ №2:
Основная причина, по которой вызов #new
( #build
это просто псевдоним для #new
) изменяет получателя, — это простота.
Например, он позволяет автоматически сохранять:
person = Person.new
person.pets.build(name: 'Spot')
person.pets.build(name: 'Professor Fluffy')
person.save!
Это приведет к вставке как person, так и двух строк в таблицу pets. Он также позволяет создавать поля формы для вложенных записей:
def new
@person = Person.new
5.times { @person.pets.new }
end
Это позволяет нам просто вызывать @person.pets
, чтобы получить записи, которые мы «посеяли»:
<%= form_with(model: @person) do |f| %>
<%= fields_for :pets do |pet_fields| %>
# ...
<% end %>
<% end %>
Если #new
бы получатель не мутировал, нам пришлось бы собрать все записи, которые мы посеяли, и каким-то образом передать их в форму. Это было бы очень неудобно, если бы у вас было несколько форм на одной странице.
Комментарии:
1. Спасибо за ответ. точно, если он не мутирует, мы должны их собрать. Я многому научился у вас