Rails 4 удаляет вложенные атрибуты, работает над созданием, но не при редактировании/обновлении
Итак, я работаю из этого Railscast.
И я знаю, что в Rails 4 произошли некоторые изменения для параметров Strong.
Первый актуальный вопрос.
Второй актуальный вопрос
Я проверил четвертую проверку своей реализации, но не вижу, где я ошибаюсь. Как и в настоящий момент, пометка "уничтожить" поле при отправке пациента изначально (т.е. Метод создания) работает по назначению и будет удалять любое лекарство, у которого есть флажок, и разрешать любое, что не имеет (из трех входных данных формы он обеспечивает).
Однако, когда я впоследствии отредактирую этого пациента, любые лекарства, которые не делают, проверяются для удаления, дублируются (поэтому я получаю больше приложенных лекарств, чем я начал), и все, что есть проверено на удаление, похоже, не меняется.
Итак, если есть две лекарства, прикрепленные "Med1" и "Med2" , и я редактирую пациента, если оба отмечены для удаления, я все равно получаю "Med1" и "Med2" . Если для удаления помечено только "Med1" , я получаю "Med1" и "Med2" и дополнительную "Med2" . Если ни один из них не помечен для удаления, я в итоге получаю по два из них "Med1" и "Med2" .
#patient.rb
class Patient < ActiveRecord::Base
has_many :procedures
has_many :medications, dependent: :destroy
has_many :previous_operations, dependent: :destroy
accepts_nested_attributes_for :medications, :allow_destroy => true, :reject_if => lambda { |a| a[:name].blank? },
end
#views/patients/_form.html.erb
<%= form_for(@patient) do |f| %>
<% if @patient.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@patient.errors.count, "error") %> prohibited this patient from being saved:</h2>
<ul>
<% @patient.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.fields_for :medications do |builder| %>
<%= render "medication_fields", :f => builder %>
<% end %>
<div class="field">
<%= f.label :first_name %><br>
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %><br>
<%= f.text_field :last_name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
#views/patients/medications_fields.html
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :_destroy, "Remove Medication" %>
<%= f.check_box :_destroy %>
</div>
#controllers/patients_controller.rb
class PatientsController < ApplicationController
before_action :set_patient, only: [:show, :edit, :update, :destroy]
# GET /patients
# GET /patients.json
def index
@patients = Patient.all
end
# GET /patients/1
# GET /patients/1.json
def show
end
# GET /patients/new
def new
@patient = Patient.new
3.times { @patient.medications.build }
end
# GET /patients/1/edit
def edit
end
# POST /patients
# POST /patients.json
def create
@patient = Patient.new(patient_params)
respond_to do |format|
if @patient.save
format.html { redirect_to @patient, notice: 'Patient was successfully created.' }
format.json { render action: 'show', status: :created, location: @patient }
else
format.html { render action: 'new' }
format.json { render json: @patient.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /patients/1
# PATCH/PUT /patients/1.json
def update
respond_to do |format|
if @patient.update(patient_params)
format.html { redirect_to @patient, notice: 'Patient was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: @patient.errors, status: :unprocessable_entity }
end
end
end
# DELETE /patients/1
# DELETE /patients/1.json
def destroy
@patient.destroy
respond_to do |format|
format.html { redirect_to patients_url }
format.json { head :no_content }
end
flash[:notice] = "Patient was successfully deleted."
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit(:first_name, :last_name, medications_attributes: [:name, :_destroy])
end
end
Я был очень осторожен и проверен более миллиона раз: _destroy флаг разрешен через сильные параметры, но все равно не кости.
Любая помощь, которую оценили, должна быть чем-то очевидным, чего я просто не вижу.
ИЗМЕНИТЬ
Изменение этого...
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit(:first_name, :last_name, medications_attributes: [:name, :_destroy])
end
Для этого...
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit!
end
похоже, работает правильно, поэтому я все еще уверен, что это что-то связано с сильными параметрами, но последнее менее безопасно. Я уверен, а не лучшая практика.
Ответы
Ответ 1
когда вы делаете
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit!
end
он разрешает все ваши атрибуты и не рекомендуется. Это скорее хак, а не решение.
Если вы посмотрите на свой вопрос
Rails 4 deleting nested attributes, works on create but not on edit/update
и если вы посмотрите на свои параметры, разрешенные
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit(:first_name, :last_name, medications_attributes: [:name, :_destroy])
end
Это будет работать на создание пациентов, но не на обновление или редактирование их, потому что, когда вы создаете новую запись, не требует разрешения id, но когда вы захотите для обновления или редактирования записи вам нужен ее идентификатор.
Fix:
Просто передайте атрибут id для разрешенных атрибутов, и он будет работать для вас
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit(:id, :first_name, :last_name, medications_attributes: [:id,:name, :_destroy])
end