Modify Ruby Hash in Place( Rails Strong Params)

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.

How to permit hash with rails strong params

You haven't mentioned the version of rails you are using but,
:elements => [] does not work because elements is a ruby hash and not an array

on rails 5.1+ you can use

params.require(:category).permit(:name, :body, :elements => {}) 

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?

update params hash in rails

Something like this would do the job:

if (attributes = params.dig(:user, :friend_attributes))
%i[players leaders].each do |key|
next unless attributes.has_key?(key)
attributes[key] = attributes[key].split(',').map(&:to_i)
end
end

The problem currently lies in (friend_params.dig(:friend_attributes) || []).each which loops though the key-value pairs, or if not present through an empty array. You then call the #[] method on the value (which is a string). eg. "50589,50590"['players'] tries the find the substring 'players' inside "50589,50590" the result of this should be nil. Followed by an "NoMethodError: undefined method `split' for nil:NilClass" exception.

You should simply use the returned collection, rather than looping through the key-value pairs.


The better question is, why do you need to transform your parameters at all?

Can't the view be arranged in such a way to provide the parameters in array format?

<input name="user[friend_attributes][players][]" type="checkbox" value="1" />
<input name="user[friend_attributes][players][]" type="checkbox" value="2" />
<input name="user[friend_attributes][players][]" type="checkbox" value="3" />

Would send an array of numbers to the controller to start with, eliminating the need to convert parameters into the correct format.

Note: If you supply the parameters in the above format you should update your permited params to:

params.require(:user).permit(:first_name, :last_name, friend_attributes: [:phone_number, :title, :role, players: [], leaders: []])
# players and leaders are now expecting an array instead of a scalar value

Strong parameters with nested hash

It's done with syntax like:

answers_attributes: [:id, :content]

The problem is the keys you are using in the answers_attributes. They are expected to be the ids of the answers_attributes or in the case of new records 0.

Changing these gives your expected outcome:

json = {
id: 1,
answers_attributes: {
"1": { id: "", content: "Hi" },
"2": { id: "", content: "Ho" }
}
}

params = ActionController::Parameters.new(json)

params.permit(:id, answers_attributes:[:id, :content])
=> {"id"=>1, "answers_attributes"=>{"1"=>{"id"=>"", "content"=>"Hi"}, "2"=>{"id"=>"", "content"=>"Ho"}}}

Edit: It appears that 0 is not the only key, I mean what if you have two new records. I use nested_form and it appears to use a very long random number.

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:

Sample Image

Sample Image

Sample Image

--

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

Strong params on a hash or array

It's possible to use strong parameters outside of controllers per the documentation at https://github.com/rails/strong_parameters

Example:

def update_user_ex(*attrs)
params = ActionController::Parameters.new(attrs)
user.assign_attributes(params.permit(:name, :email, :something_else))


Related Topics



Leave a reply



Submit