Rails 5 - Manually add attribute to parameters in controller when updating
Solution 1
In general its a good practice to view the incoming parameters as unmutable. It makes debugging and reasoning about your controller code much simpler.
There are a few tricks you can to do to avoid monkeying with the params.
Use a block:
# this works for .new and .create as well
updated = @actual.update(actual_params) do |a|
a.foo = current_user.foo
a.b = params.fetch(:foo, "some default")
end
Use composition to create safe parameters methods.
def common_params
[:name, :title]
end
def create_params
params.require(:model_name)
.permit(*common_params, :foo)
end
def update_params
params.require(:model_name)
.permit(*common_params, :bar)
end
Using .except
can be risky since its better to whitelist than blacklist as you may forget to add future attributes to the blacklist.
Solution 2
You're using merge
which
Returns a new
ActionController::Parameters
with all keys fromother_hash
merged into current hash
and you're not storing the new ActionController::Parameters
into anything. You can instead use merge!
which
Returns current
ActionController::Parameters
instance withother_hash
merged into current hash.
actual_params.merge!(:file_name => 'ted.png')
if actual_params
is a method on your controller instead of an object (the name threw me the first time, but seeing the model name is probably Actual
, a method makes more sense now), you'll need to store the return value into a new hash to work with:
new_params = actual_params.merge(:file_name => 'ted.png')
new_params = new_params.except(:facesheet)
@actual.update(new_params)
This is because each time you call a method that's defined like:
def actual_params
params.require(:actual).permit(:factsheet, *whatever_else)
end
it's returning a new, different ActionController::Parameters
each time so mutating the one still doesn't work if you don't save it anywhere
Solution 3
Try something like
private
def post_params
params.require(:post).permit(:some_attribute).merge(user_id: current_user.id)
end
Solution 4
Try to whitelist the params instead of using .except
Also try to use .permit() to whitelist the required params
Matt Ellis
Updated on June 13, 2022Comments
-
Matt Ellis almost 2 years
I am trying to manually add an additional attribute to parameters in the controller after completing a form. The params seem to be wrapped in , which seems to be preventing me to from changing the params.
Controller:
class ActualsController < SignedInController ... def update respond_to do |format| facesheet = actual_params[:facesheet] #trying to manually add attribute actual_params.merge(:file_name => 'ted.png') new_params = actual_params.except(:facesheet) if @actual.update(new_params) format.html { redirect_to action: 'show', id:@actual.id, notice: 'Actual was successfully updated.' } format.json { render :show, status: :ok, location: @actual } else format.html { render :edit } format.json { render json: @actual.errors, status: :unprocessable_entity } end end end ... end
"new_params" from console
<ActionController::Parameters {"encounter_type_id"=>"1", "physician_id"=>"669", "insurance_id"=>"1182", "time_start"=>"05:00", "time_end"=>"07:00", "date_start"=>"2017-08-02", "date_end"=>"2017-08-02", "facility_id"=>"1", "med_rec_num"=>"1244", "patient_name_first"=>"Bob", "patient_name_last"=>"Smith", "patient_name_middle_initial"=>"H", "patient_dob"=>"2000-02-05", "note"=>"", "is_complete"=>"0", "procedure_ids"=>["", "300"]} permitted: true> -Thanks for your help on this.
"@actual" from console
#<Actual id: 18, encounter_id: 4, provider_id: 7, encounter_type_id: 1, physician_id: 669, facility_id: 1, insurance_id: 1182, group_id: nil, datetime_start_utc: "2017-08-02 10:00:00", datetime_end_utc: "2017-08-02 12:00:00", payer: nil, med_rec_num: "1244", patient_name_first: "Bob", patient_name_last: "Smith", patient_name_middle_initial: "H", patient_dob: "2000-02-05", finclass: nil, is_valid: nil, is_complete: false, image_location: nil, note: "", created_at: "2017-08-18 13:30:58", updated_at: "2017-08-18 16:01:28">
-
Matt Ellis over 6 yearsJust added the "!" for merge, but still not getting it to add the attribute ---- > actual_params.merge!(:file_name => 'teddy.png')
-
Simple Lime over 6 yearsWhy's that @max ? And @MattEllis, is
actual_params
a method or an object? -
max over 6 yearsBecause mutating the params makes it harder to debug - sudddenly down the line the params are not the same as what you see in the logs. Its better to use
.merge
which is non-destructive. -
Matt Ellis over 6 years@SimpleLime --> actual_params is an object