I am currently trying to permit params containing an array object.
#My controller
def students_params
params.require(:student).permit(standards:[], subjects: [])
end
So here in my case, I will have a list of params names to be permitted.
Consider I have a constant which has list as below:
STUDENTS_PARAMS = ['standands', 'subjects', 'grade', .....]
I tried doing this as below:
#My controller
def students_params
params.require(:student).permit(*STUDENTS_PARAMS)
end
Problem here is params with array value and getting included.
Instead of adding all fields manually is there any other way, I can achieve this?
Thanks you
I take it that you meant to say Problem here is params with array value and ARENT getting included., which is to be expected because its looking for a hash not a symbol/string.
What if you try passing
STUDENTS_PARAMS = [{standands: []}, {subjects: []}, 'grade']
def students_params
params.require(:student).permit(*STUDENTS_PARAMS)
end
Related
I have an array of parameters and i want to replace all parameters by looping over array in ruby on rails.
I am using before_action in controller as
before_action :cost_format
This is an array of parameters. The format of the parameter is string, i want to run a function on each parameter and convert it into float. So i am looping an array and calling function on each element.
def cost_format
x = [params[:cost_1], params[:cost_2], params[:cost_3]]
x.each do |i|
convert_cost(i)
end
end
I have a function convert_cost as following
def convert_cost(x)
x.gsub(',', '.').to_f
end
How do i loop an array so that my parameters get replaced.? Parameters are not being replaced by above code. Any hint would be appreciated.
Thanks
I think you'll want something like this:
def cost_format
%i(cost_1 cost_2 cost_3).each do |key|
params[key] = convert_cost(params[key])
end
end
def convert_cost(val)
val.gsub(',', '.').to_f
end
This grabs each key from your params and replaces the value with it passed through the convert_cost method.
Edit: you might be able to ignore this section about convert_cost due if it works with the format you're getting your numbers in. Please excuse my ethnocentrism :)
I've not updated your convert_cost method, though I'm a little wary about whether it will work at the moment. If you've got, for example "1,234,567" and you call your gsub you get "1.234.567". Calling to_f on that gives you 1.234, which I wouldn't think you'd want?
Instead of that, you could use:
def convert_cost(val)
val.gsub(',', '').to_f
end
E.G.
convert_cost("1,234,567")
# => 1234567.0
Combining all that, the following would be converted like so:
params = { cost_1: "1,234,567", cost_2: "123", cost_3: "456.5", cost_4: "I won't be touched" }
# after `cost_format` before_action runs:
# => {:cost_1=>1234567.0, :cost_2=>123.0, :cost_3=>456.5, :cost_4=>"I won't be touched"}
Let me know how you get on or if you have any question - hope this helps.
Could you try something like
x.map{|param| param.gsub(',', '.').to_f}
directly on your array.
So your cost_format method will look like:
def cost_format
x = [params[:cost_1], params[:cost_2], params[:cost_3]]
result = x.map{|param| param.gsub(',', '.').to_f}
# do stuff with result
end
I think the reason it's not working because, each method returns its receiver, but map returns a new array.
In Rails 4.2, I'd like to validate that every hash of an array passed as a parameter to my action has certain attributes.
For now I could only find how to filter out unwanted attributes, such as:
ActionController::Parameters.new(
points: [{lat: 42, foo: 0}, {lng: 43, bar: 100}]
).permit(
points: [:lat, :lng]
)
# => {"points"=>[{"lat"=>42}, {"lng"=>43}]}
What I'd like to do is making sure every member of points has both lat and lng without having to loop over it. Is this possible using permit or a similar method?
There is a method called require that has the same signature as permit:
params.require(:lat, :lng)
Note that you can chain this with permit
Also, you can use select or reject on the params hash, secure params is mostly sugar for this anyway.
def my_params
required_attrs = %w{lat lng}
missing_params = required_attrs.select do |key|
params.has_key?(key)
end
missing_params.empty? ? params : raise(RuntimeError, "missing params: #{missing_params.join(",")}")
end
I'm working in Ruby on Rails and I'm trying to permit all values from a hash using Ruby's permit function. It seems rather simple, but I just cannot get this to work. I've already reviewed the references on permit, and answers to this SO question how to permit an array with strong parameters.
Here's my code
PERMITTED_PARAMS = [
:OriginCity,
:OriginState,
{ :PickupDates => {}}
].freeze
params = {"OriginCity"=>"Denver", "OriginState"=>"CO", "PickupDates"=>{"0"=>"2016-09-30"}}
filtered_params = params.permit(PERMITTED_PARAMS)
And, the resulting value for filtered_params is
{"OriginCity"=>"Denver", "PickupDates"=>{}}
While the desired value for filtered_params is
{"OriginCity"=>"Denver", "PickupDates"=>{"0":"2016-09-30"}}
Any advice on how to obtain the desired value by changing PERMITTED_PARAMS?
You want to permit all values in a hash, not an array, which is different from the example you linked to.
Try this:
PERMITTED_PARAMS = [
:OriginCity,
:OriginState
].freeze
params = {"OriginCity"=>"Denver", "OriginState"=>"CO", "PickupDates"=>{"0"=>"2016-09-30"}}
filtered_params = params.permit(PERMITTED_PARAMS).tap do |whitelisted|
whitelisted[:PickupDates] = params[:PickupDates]
end
See also: Strong parameters: allow hashes with unknown keys to be permitted
Assume we have a rails params hash full of nested hashes and arrays. Is there a way to alter every string value (whether in nested hashes or arrays) which matches a certain criteria (e.g. regex) and still keep the output as a params hash (still containing nested hashes arrays?
I want to do some sort of string manipulation on some attributes before even assigning them to a model. Is there any better way to achieve this?
[UPDATE]
Let's say we want to select the strings that have an h in the beginning and replace it with a 'b'. so we have:
before:
{ a: "h343", b: { c: ["h2", "s21"] } }
after:
{ a: "b343", b: { c: ["b2", "s21"] } }
For some reasons I can't do this with model callbacks and stuff, so it should have be done before assigning to the respective attributes.
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
In general you should not alter the original params hash. When you use strong parameters to whitelist the params you are actually creating a copy of the params - which can be modified if you really need to.
def whitelist_params
params.require(:foo).permit(:bar, :baz)
end
But if mapping the input to a model is too complex or you don't want to do it on the model layer you should consider using a service object.
Assuming you have a hash like this:
hash = { "hello" => { "hello" => "hello", "world" => { "hello" => "world", "world" => { "hello" => "world" } } }, "world" => "hello" }
Then add a function that transforms the "ello" part of all keys and values into "i" (meaning that "hello" and "yellow" will become "hi" and "yiw")
def transform_hash(hash, &block)
hash.inject({}){ |result, (key,value)|
value = value.is_a?(Hash) ? transform_hash(value, &block) : value.gsub(/ello/, 'i')
block.call(result, key.gsub(/ello/, 'i'), value)
result
}
end
Use the function like:
new_hash = transform_hash(hash) {|hash, key, value| hash[key] = value }
This will transform your hash and it's values regardless of the nesting level. However, the values should be strings (or another Hash) otherwise you'll get an error. to solve this problem just change the value.is_a?(Hash) conditional a bit.
NOTE that I strongly recommend you NOT to change the keys of the hash!
Is it possible to dynamically create key names of a hash? I'm passing the following hash parameters:
params[:store][:store_mon_open(5i)]
params[:store][:store_mon_closed(5i)]
params[:store][:store_tue_open(5i)]
params[:store][:store_tue_closed(5i)]
.
.
.
params[:store][:store_sun_open(5i)]
params[:store][:store_sun_closed(5i)]
To check if each parameter exists, I'm using two arrays:
days_of_week = [:mon, :tue, ..., :sun]
open_or_closed = [:open, :closed]
But, I can't seem to figure out how to dynamically create the params hash (the second key( with the array. Here's what I have so far:
days_of_week.each do |day_of_week|
open_or_closed.each do |store_status|
if !eval("params[:store][:store_#{day_of_week}_#{store_status}(5i)").nil
[DO SOMETHING]
end
end
end
I've tried a bunch of things including the eval method (as listed above) but rails seems to dislike the parentheses around the "5i". Any help is greatly appreciated!
You should be able to do
if params[:store]["store_#{day_of_week}_#{store_status}(5i)".to_sym]
Note that you were missing the ? on .nil? and that !object.nil? can be shortened to just object
Assuming this is a HashWithIndifferentAccess, you should be able to access it via string just as you could with a symbol. Thus:
days_of_week.each do |day_of_week|
open_or_closed.each do |store_status|
key = "store_#{day_of_week}_#{store_status}(5i)"
unless params[:store][key]
# DO SOMETHING
end
end
end
If it's not a HashWithIndifferentAccess then you should just be able to call key.to_sym to turn it into a symbol.