So I'm working from this Railscast.
我在轨道广播公司工作。
And I'm aware that there have been some changes in Rails 4 for Strong parameters.
我知道Rails 4对于强参数有一些变化。
第一个相关的问题。
第二个相关的问题
I've quadruple checked my implementation, but can't see where I'm going wrong. As it is at the moment, ticking the "destroy" box when submitting the patient initially (i.e. the create method) works as intended, and will delete any medication that has a checked box and permitting any that does not (from the three form inputs it provides).
我检查了我的实现四倍,但是不知道哪里出错了。就像目前的情况一样,在最初提交病人的时候勾选“销毁”框(即创建方法),并将删除任何有复选框的药物,并允许任何没有的药物(从它提供的三个表单输入中)。
However when I subsequently edit that patient, any medications that don't get checked to be deleted are duplicated (so I end up with more attached medications than I started with), and any that are checked for deletion don't seem to change.
然而,当我随后编辑那个病人时,任何未经检查而被删除的药物都是重复的(因此我最终得到的附加药物比开始时更多),任何被检查为删除的药物似乎都不会改变。
So if there two medicines attached "Med1" and "Med2", and I edit the patient, if both are marked for deletion I will still end up with "Med1" and "Med2". If only "Med1" is marked for deletion I will end up with "Med1" and "Med2" and an extra "Med2". If neither are marked for deletion I will end up with two each of "Med1" and "Med2".
因此,如果有两种药物附着在“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
I've been super careful and checked over a million times the :_destroy flag being allowed through strong parameters, but still no dice.
我已经非常小心地检查了超过一百万次:_destroy标志被允许通过强参数,但是仍然没有骰子。
Any help appreciated, must be something obvious that I just can't see.
任何帮助都是显而易见的,我就是看不见。
EDIT
编辑
Changing this...
改变这种……
# 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
To this...
这……
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit!
end
appears to work correctly, so I'm still sure it's something to do with strong parameters, but the latter is less secure I'm sure and not best practice.
看起来是正确的,所以我仍然确信这与强参数有关,但我确信后者不那么安全,也不是最佳实践。
1 个解决方案
#1
33
when you are doing
当你正在做的事情
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit!
end
it permits all of your attributes and it's not recommended. It's more of a hack rather than a solution.
它允许您的所有属性,但不建议这样做。这与其说是解决方案,不如说是一种技巧。
If you look at your question
如果你看看你的问题
Rails 4 deleting nested attributes, works on create but not on edit/update
Rails 4删除嵌套属性,可用于创建,但不能用于编辑/更新
and if you look at your params permitted
如果你看看允许的参数
# 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
This will work on creating patients but not on updating or editing them because when you create a new record it doesn't require you to permit id but when you want to update or edit a record you need its id to be permitted as well.
这将用于创建患者,而不是更新或编辑患者,因为当您创建一个新记录时,它不需要您允许id,但是当您想要更新或编辑一个记录时,您也需要允许它的id。
Fix:
解决办法:
Just pass the id attribute to permitted attributes and it will work for you
只要将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
#1
33
when you are doing
当你正在做的事情
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit!
end
it permits all of your attributes and it's not recommended. It's more of a hack rather than a solution.
它允许您的所有属性,但不建议这样做。这与其说是解决方案,不如说是一种技巧。
If you look at your question
如果你看看你的问题
Rails 4 deleting nested attributes, works on create but not on edit/update
Rails 4删除嵌套属性,可用于创建,但不能用于编辑/更新
and if you look at your params permitted
如果你看看允许的参数
# 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
This will work on creating patients but not on updating or editing them because when you create a new record it doesn't require you to permit id but when you want to update or edit a record you need its id to be permitted as well.
这将用于创建患者,而不是更新或编辑患者,因为当您创建一个新记录时,它不需要您允许id,但是当您想要更新或编辑一个记录时,您也需要允许它的id。
Fix:
解决办法:
Just pass the id attribute to permitted attributes and it will work for you
只要将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