50

This may be more a ruby question then rails question but I'm pretty sure I was able to do this in a vanilla ruby application.

I have strong params defined.

def trip_params
  params.require(:trip).permit(:name, :date)
end

Now I get those params in a controller method. I want to do this.

def save
  trip_params[:name] = 'Modifying name in place'
  #trip_params[:name] still equals original value passed
end

This never works. Name never changes. BTW: The type of trip_params is ActionController::Parameters

If I do a standard ruby script, it works.

test = {}    
test[:name] = "blah"    
test[:name] = "ok"    
puts test #{:name=>"ok"}
Drew H
  • 4,699
  • 9
  • 57
  • 90
  • Is Trip an active record? You may need to explicitly save it in the database: `@trip.save` – Daiku Aug 22 '13 at 00:14
  • I took the Trip.new part. Don't let that distract. I'm trying to modify the ActionController::Parameters hash in place. – Drew H Aug 22 '13 at 00:42

4 Answers4

71

permit returns a new hash with those keys in it, so you're not modifying the real params variable. You're also not saving a reference to the hash trip_params returns, so you get it fresh each call in save.

Try this:

def save
  tp = trip_params
  tp[:name] = 'Modifying name in place'
  # ... use tp later, it'll be in there
end

Or, if you really want it to be used the way you previously did, modify trip_params like so:

def trip_params
  @trip_params ||= params.require(:trip).permit(:name, :date)
end

Now that hash is lazily cached and the same one is returned on subsequent trip_params calls.

Nick Veys
  • 23,458
  • 4
  • 47
  • 64
30

If you really want to change params in controller you can do it on this way:

def save
  params[:trip][:name] = 'Modifying name in place'
  # Now trip_params[:name] is 'Modifying name in place'
end
Иван Бишевац
  • 13,811
  • 21
  • 66
  • 93
  • 11
    I think this is the best and simplest answer here. Just modify the actual params first, then call your strong parameters method. You can even do it with before_action :modify_params, only [:create, :update] then create a private method to keep it out of your create and update methods. – scottknight Sep 18 '15 at 23:07
6

You could also do

def save
  data = trip_params.merge(name: 'new name')
  # use data later
end

If a new hash is merged into an old hash and if there are duplicate keys, the new hash's keys overwrite the old hash's matching keys.

Nithin
  • 3,679
  • 3
  • 30
  • 55
Cruz Nunez
  • 2,949
  • 1
  • 23
  • 33
3

This is because there's no method such as trip_params[]=(arg, val).

I mean, when you call trip_params you are returning the value of params.require(:trip).permit(:name, :date), so every time you call trip_params you are getting the params again.

So, if I were you, I'd define the trip_params method as follow:

def trip_params
  @trip_params ||= params.require(:trip).permit(:name, :date)
end

And would also define a method to change trip_params

def trip_params[]= (key,val)
  trip_params # Ensure that trip_params is called once or you will get an error
  @trip_params[key] = val
end

So now when you call trip_params you would actually return @trip_params, and if @trip_params is not set yet it would set to params.require(:trip).permit(:name, :date)

And then when you call trip_params[:name] = "Some name" it will ensure first that @trip_params is initialized by calling trip_params and then it will set the :name param to"Some name"`

Hope I've helped you

Bernardo Amorim
  • 343
  • 1
  • 6