assign/replace params hash in rails
The params
which contains the request parameters is actually a method call which returns a hash containing the parameters. Your params =
line is assigning to a local variable called params
.
After the if false
block, Ruby has seen the local params
variable so when you refer to params
later in the method the local variable has precedence over calling the method of the same name. However because your params =
assignment is within an if false
block the local variable is never assigned a value so the local variable is nil
.
If you attempt to refer to a local variable before assigning to it you will get a NameError:
irb(main):001:0> baz
NameError: undefined local variable or method `baz' for main:Object
from (irb):1
However if there is an assignment to the variable which isn't in the code execution path then Ruby has created the local variable but its value is nil
.
irb(main):007:0> baz = "Example" if false
=> nil
irb(main):008:0> baz
=> nil
See: Assignment - Local Variables and Methods in the Ruby docs.
Rails 6 change params to hash of hashes
The params get his structure from the input names.
So you could add an hidden field for question, and then specify a name for both of your fields.
<%= simple_form_for :test_results, url: test_results_path do |f| %>
<% @randomize_questions.map do |q| %>
<%= q[:question] %>
<%= f.input "question_#{q[:id]}", as: :hidden, input_html: { name: "test_results[#{q[:id]}][question]", value: q[:question] } %>
<%= f.input "question_#{q[:id]}", collection: q[:answers], as: :radio_buttons, input_html: { name: "test_results[#{q[:id]}][answer]" } %>
<% end %>
<%= f.button :submit %>
<% end %>
Params should looks like this:
params => {
test_result: {
1 => {
question: "...",
answer: "..."
},
2 => {
question: "...",
answer: "..."
}
}
}
Not tested. Could you tell if that's works for you?
Modify ruby hash in place( rails strong params)
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.
Modifying the params hash in Rails
The params hash is special since (especially with forms) is it mapped one-for-one with the model(s) it is related to, and Rails expects there to be either a database column, or a method in the model having that name.
Hidden fields are the typical solution to the problem of getting at additional data, but if you don't want users to see those fields, you run into the problem that HTTP is stateless. So in this case, the session[:something]
is your friend. Before displaying a form or page that may have hidden data, instead add the data to a session variable (encrypt it first), which you can then read (and decrypt) when the user submits the form. Or you can save it in a database table and put only the row id in the session so the data can be read back when the form is posted.
If the data was part of the model, but you just didn't want to display it, you could just display the parts the user could see in the view, but then look up the rest of it in the controller action when the user submitted the form or request.
If the data is not sensitive you can just make sure to declare the values that the user can change as attr_accessible
in their respective models (prevents mass assignment) and put the others in hidden fields.
Editing params nested hash
still keep the output as a params hash (still containing nested hashes arrays
Sure.
You'll have to manipulate the params
hash, which is done in the controller.
Whilst I don't have lots of experience with this I just spent a bunch of time testing -- you can use a blend of the ActionController::Parameters
class and then using gsub!
-- like this:
#app/controllers/your_controller.rb
class YourController < ApplicationController
before_action :set_params, only: :create
def create
# Params are passed from the browser request
@model = Model.new params_hash
end
private
def params_hash
params.require(:x).permit(:y).each do |k,v|
v.gsub!(/[regex]/, 'string')
end
end
end
I tested this on one of our test apps, and it worked perfectly:
--
There are several important points.
Firstly, when you call a strong_params
hash, params.permit
creates a new hash out of the passed params. This means you can't just modify the passed params with params[:description] =
etc. You have to do it to the permitted params.
Secondly, I could only get the .each
block working with a bang-operator (gsub!
), as this changes the value directly. I'd have to spend more time to work out how to do more elaborate changes.
--
Update
If you wanted to include nested hashes, you'd have to call another loop:
def params_hash
params.require(:x).permit(:y).each do |k,v|
if /_attributes/ ~= k
k.each do |deep_k, deep_v|
deep_v.gsub!(/[regex]/, 'string'
end
else
v.gsub!(/[regex]/, 'string')
end
end
end
How to change value in params array in Ruby on Rails?
If vendor_params is a strong_params method (which I'm assuming it is), it actually creates a new hash. So when you alter vendor_params... you're not actually changing your original params hash.
OK, why isn't vendor_params changing though... I dont care about params? WELL, vendor_params still points the original params hash assuming it looks something like:
def vendor_params
params.require(:vendor).permit(:price)
end
I think the link below is a similar issue and may present a useful solution. Hope I understood your problem correctly!
Modify ruby hash in place( rails strong params)
How to replace a hash key with another key
hash[:new_key] = hash.delete :old_key
How to change Hash values?
my_hash.each { |k, v| my_hash[k] = v.upcase }
or, if you'd prefer to do it non-destructively, and return a new hash instead of modifying my_hash
:
a_new_hash = my_hash.inject({}) { |h, (k, v)| h[k] = v.upcase; h }
This last version has the added benefit that you could transform the keys too.
Rails Controller action: Customize key in params hash
This is currently very wrong.
In order to make this work as it should, you should create a route like this
resources :widgets do
get 'comments' => 'comments#index'
post 'comments' => 'comments#create'
end
and when posting to this CommentsController
, you pass in the comment info correctly in the prams[:comment]
.
Your controller would have actions like this
def create
widget = Widget.find(params.delete :widget_id)
comment = widget.comments.create(params[:comment])
end
Related Topics
Create Custom HTML Helpers in Ruby on Rails
Loaderror Running Mongrel with Rails3 and Ruby 1.9.2
Does Ruby Call Initialize Method Automatically
Converting from Xml Name-Values into Simple Hash
Has Anyone Successfully Deployed a Rails Project with Ruby 1.9.1
Error: While Executing Gem ... (Zlib::Gzipfile::Error) Not in Gzip Format
How Is a Local Variable Created Even When If Condition Evaluates to False in Ruby
Ruby: Inject Issue When Turning Array into Hash
What's the Best/Easiest Gui Library for Ruby
Rails - Local Variables Versus Instance Variables
Redirect User After Log in Only If It's on Root_Path
Using Rbenv Doesn't Work with Sudo
Parse Email Addresses for "From" and "To" Fields in Ruby