I have the following method in one of my Ruby on Rails apps controllers:
decoded_translations = params[:translations].collect do |encoded_source, encoded_translation|
decoded_source = URI.decode(encoded_source).gsub("\r\n", "\n")
decoded_translation = URI.decode(encoded_translation).gsub("\r\n", "\n")
[decoded_source, decoded_translation]
end
When I run my tests this returns me:
undefined method `collect' for #<ActionController::Parameters:0x007ff0e810c6e8>
How can I fix this?
Before using collect method on array/hash comming in the paramters, you have permit the required param and convert it to array/hash. Then only we can able to apply collect method on it.
Ex:
permit_params = params.permit(refresh: [:key, :scope, types: []])
permit_params[:refresh].methods.grep /collect/
# => []
permit_params[:refresh].to_h.methods.grep /collect/
# => [:collect, :collect_concat]
params[:refresh].to_h
# => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
# from /Users/mohanrajr/.rbenv/versions/2.2.2/gemsets/<app>/gems/actionpack-5.1.2/lib/action_controller/metal/strong_parameters.rb:258:in `to_h'
Related
Getting this error when trying to call the method validate_create_action. The error occurs on the line #element = klass.new(params[:element]).
NoMethodError in Analyses::MitigationMatricesController#validate_create_action
undefined method `map' for #<ActionController::Parameters {"0"=>{"phase"=>"Launch", "reason"=>"test"}} permitted: false>
Did you mean? tap
Extracted source (around line #7):
#5 class ManyEmbeddedProxy < EmbeddedCollection
#6 def replace(values)
*7 #_values = (values || []).compact.map do |v|
#8 v.respond_to?(:attributes) ? v.attributes : v
#9 end
#10 reset
In the post request the element object below is sent to the backend. The issue seems to be the array critical_phases.
element[applicable_during][critical_phases][0][phase] "Launch"
element[applicable_during][critical_phases][0][reason] "test"
If I add the method to_unsafe_h to params[:element].to_unsafe_h I get a different error involving the critical_phases array saying "TypeError: no implicit conversion of String into Integer". Any ideas on how to solve this?
element_controller.rb
def validate_create_action
rejigger_dynamic_lists
remove_associations_from_params
#element = klass.new(params[:element])
...
def klass
unless #klass
klass_str = params[:controller].split("/").last.singularize.camelize
namespace_str = SITE_CONFIG['adaptation_name'].camelize
#klass = "#{namespace_str}::#{klass_str}".constantize
end
#klass
end
UPDATE:
I updated my code to the working code
params[:element].permit!
params2 = ActionController::Parameters.new(params[:element][:applicable_during][:critical_phases].to_h)
params2.permit!
params[:element][:applicable_during][:critical_phases] = params2.values.map do |h|
ActionController::Parameters.new(h.permit!.to_h).permit(:phase, :reason) # use permit! instead if you want to live dangerously
test_mapping = {}
end
The problem here is that it the parameters aren't actually an array. Its a hash with the keys "0", "1" etc. This is done to avoid the potential ambigiuty thats happens when Rack parses form data keys containing arrays of hashes:
irb(main):015:0> Rack::Utils.parse_nested_query("foo[][bar]=1&foo[][bar]=2")
=> {"foo"=>[{"bar"=>"1"}, {"bar"=>"2"}]}
# should this be one or two hashes? Discuss
irb(main):016:0> Rack::Utils.parse_nested_query("foo[][bar]=1&foo[][baz]=2")
=> {"foo"=>[{"bar"=>"1", "baz"=>"2"}]}
irb(main):017:0> Rack::Utils.parse_nested_query("foo[0][bar]=1&foo[1][baz]=2")
=> {"foo"=>{"0"=>{"bar"=>"1"}, "1"=>{"baz"=>"2"}}}
Typically normalizing this is handled by accepts_nested_attributes_for. But what you're doing doesn't look the least bit ordinary.
If you want to jury rig a system that processes this and returns an array of whitelisted hashes you could do:
params = ActionController::Parameters.new("0"=>{"phase"=>"Launch", "reason"=>"test"}, "1"=>{"phase"=>"Foo", "reason"=>"bar"})
params.values.map do |h|
ActionController::Parameters.new(h)
.permit(:phase, :reason) # use permit! instead if you want to live dangerously
end
# [<ActionController::Parameters {"phase"=>"Launch", "reason"=>"test"} permitted: true>, <ActionController::Parameters {"phase"=>"Foo", "reason"=>"bar"} permitted: true>]
I have an object and want to access to some data but I have an error.
This is the object:
list = [{"id"=>0,"title"=>"Purple Rain"}, {"id"=>1,"title"=>"Life is a flower"},]
With binding.pry, i tried to access to the title of the first object by:
list.first.title
Can you tell me why it doesn't work? If i do "list.first", it will show the first object without any problem but when i want to access to only one data, i got this error:
NoMethodError: undefined method `title' for #<Hash:0x...
Thanks for your help
Hash doesn't have dot syntax. OpenStructs do. If you want to use dot syntax, then you can convert to openstruct if you want. But using what Sebastian suggested is fine.
list
# => [{"id"=>0, "title"=>"Purple Rain"}, {"id"=>1, "title"=>"Life is a flower"}]
list.first["title"]
# => "Purple Rain"
require 'ostruct'
# => true
obj = OpenStruct.new(list.first)
# => #<OpenStruct id=0, title="Purple Rain">
obj.title
# => "Purple Rain"
Looking at the documentation for ActionController::Parameters for the require method I read the followiing
When given an array of keys, the method tries to require each one of them in order. If it succeeds, an array with the respective return values is returned:
params = ActionController::Parameters.new(user: { ... }, profile: { ... })
user_params, profile_params = params.require(:user, :profile)
but when I run this code with rails console, my output is very different
[70] pry(main)> params = ActionController::Parameters.new(user: { a: 1 }, profile: { b: 2 })
=> {"user"=>{"a"=>1}, "profile"=>{"b"=>2}}
[71] pry(main)> user_params, profile_params = params.require(:user, :profile)
ArgumentError: wrong number of arguments (2 for 1)
from /home/myuser/.rbenv/versions/2.1.6/lib/ruby/gems/2.1.0/gems/actionpack-4.2.1/lib/action_controller/metal/strong_parameters.rb:244:in `require'
When I read when given an array of keys and saw the example, I thought that maybe they made a mistake when writing the example, so I tried this as well, but it did not work either.
[72] pry(main)> user_params, profile_params = params.require([:user, :profile])
ActionController::ParameterMissing: param is missing or the value is empty: [:user, :profile]
from /home/myuser/.rbenv/versions/2.1.6/lib/ruby/gems/2.1.0/gems/actionpack-4.2.1/lib/action_controller/metal/strong_parameters.rb:249:in `require'
What is going on here?
You're looking at the API docs for the current version of Rails (which is Rails 5), and you're using Rails 4.2.1. The Rails 4 docs do not specify multiple arguments to require like that:
http://api.rubyonrails.org/v4.2.1/classes/ActionController/Parameters.html#method-i-require
Have you tried:
def user_params
params.require(:user)
end
def profile_params
params.require(:profile)
end
This way you have two separate rules for each model.
I am having a small problem with a method in Ruby. "information" is a hash that I want to iterate through, format the value if necessary and save a new hash with the formatted/changed pairs. The following:
formatted_information = {}
information.each do |key, value|
formatted_information[:"#{key}"] = self.send("format_#{key}(#{value})")
end
is supposed to call another method in the same document that handles the formatting (so if the key "name" was found it should run "format_name" with the corresponding value). Although the method exists I get the following error:
NoMethodError: undefined method `format_name("Some Name")'
What mistake am I making here?
Possible input:
information = {:name => "A Name"}
Expected output:
formatted_information = {:name => "B Name"}
send accepts the method name as the first argument, and the arguments to that method as the second argument. You should use
send("format_#{key}", value)
I'm trying to get these statements to work:
#all_ratings = ["G","PG","PG-13","R"]
#valid_ratings = params["ratings"]
#movies = Movie.find(:all , :conditions => {#valid_ratings[:rating.upcase] => "1"} )
but I am getting the error:
undefined method `to_sym' for nil:NilClass
when I should be getting a match.
An example input is:
"ratings"=>{"PG-13"=>"1"}
Where am I going wrong?
More info:
The table has three fields, the title, release date, and rating, and is very simple. The options for rating are stated above in #all_ratings.
Rails 3.x:
#all_ratings = ["G","PG","PG-13","R"]
#valid_ratings = params["ratings"]
# Is #valid_ratings the same as you example, "ratings"=>{"PG-13"=>"1"}?
# It would be easiest to pass a subset of #all_ratings such that the params
# get converted to something like this: "ratings"=>["G", "PG"]
Movie.where(:rating => valid_ratings).all
# SQL: SELECT * FROM movies WHERE rating IN ('G','PG')
I am not sure what you are trying to with :rating.upcase. Is there a variable named rating? :rating is a symbol. upcase is not a method on Symbol.
It tells you that you #valid_ratings in nil
You probably trying doing this?
#valid_ratings = Rating.find(params["ratings"])