Error while iterating through params - ruby-on-rails

I get an error when I try to iterate through params
When running code below:
def create_score
#quiz = Test.find_by(password: session[:test_password])
#points = 0
#quiz.tasks.each_with_index do |task, index|
#task = Task.find_by(id: task)
#points += #task.score if #task.correct_answers.to_s == send("params[:test][:task#{index}]")
end
#score = Score.new(user_id: 2, name: "Test1", points: #points)
if #score.save
redirect_to root_url
else
redirect_to signup_path
end
end
I get:
undefined method `params[:test][:task0]' ...
at the
#points += #task.score if #task.correct_answers.to_s == send("params[:test][:task#{index}]")
Which means that it has problem with send method
Parameters look like this:
{"utf8"=>"✓",
"authenticity_token"=>"8h7rtv2yWio11DFo6kBKutdZl7RDBBaTrt7e8qel8fR5R5XsoXRhRrBeDQPPoZeuBlZ7N5PmqCxik06Z/gQLZQ==",
"test"=>{"task0"=>["4"], "task1"=>["0"], "task2"=>["10"]},
"commit"=>"Zakończ test",
"locale"=>"pl"}
Which means that there is params[:test][:task0], but still for some reason it fires an error, but I don't really know why. Any ideas why this happens?

You want to index with dynamic key, not call a method dynamically. Aka:
params[:test]["task#{index}"]
Should do. Note that params are have indifferent access for strings and symbols.
To give you more food for thought, here is how you might have done the same with #send:
params[:test].send(:[], "task#{index}")
And here is how to define a method that would have the name you are trying to call:
define_method("params[:test][:task#{index}]") do
puts 'WTF'
end

You're calling your params with a symbol but instead you should use a string.
This means you should use one of the following approaches:
params["test"]["task0"]
or
params[:test.to_s][:task0.to_s]
Hope that helped :)

You should use params object something likeparams[:test][:task]) instead of send("params[:test][:task#{index}]".

Related

why no implicit conversion of nil into Hash?

after setup a search into a serializer!
Rails spits out
no implicit conversion of nil into Hash
So, please someone can point out whats wrong with this code?
class SearchController < ApplicationController
def results
results_query = PgSearch.multisearch(params[:q]).paginate(page: page, per_page: 20)
result = results_query.map(&:searchable).map do |result_item|
case result_item.class.name
when 'Post'
PostSerializer.new(result_item)
else
raise NotImplementedError
end
end
render json: {
items: result,
page: page,
pages: results_query.total_pages
}
end
def page
params[:page] || 1
end
def serialize(data, serializer)
ActiveModel::Serializer::CollectionSerializer.new(data, each_serializer: serializer)
end
end
Since your case statement isn't checking many values, you could always make it into a standard if/else statement:
if result_item && result.class.name == 'Post'
PostSerializer.new(result_item)
else
raise NotImplementedError
end
Well, on the screenshots you've provided we can see the log message specifies that the error is on line 5.
According to your code, line 5 is: case result_item.class.name
The error message is TypeError (no implicit conversion of nil into Hash).
You're trying to get the class then the name of result_item. So the problem is with result_item which is equal to nil.
In order the resolve your problem you might want to check the ouput of results_query.map(&:searchable).map.
Based on the screenshot you've provided, I've quickly checked the source code. The offending line seems to be this one: https://github.com/Casecommons/pg_search/blob/master/lib/pg_search/document.rb#L22. The only reason why this would raise the described TypeError is if PgSearch.multisearch_options is nil – which, as far as I understand the code, would only be possible if you accidentally overwrote it in a wrong way. So I'd suggest doublechecking your global setup for PgSearch.multisearch_options to make sure this is actually set.
The east way to check the setting is by using a debugger or putting something like puts PgSearch.multisearch_options or Rails.logger.info 'PgSearch.multisearch_options' into the controller directly above the call that's failing.

rails 5 ForbiddenAttributesError on bulk operations

i try to bulk operation in my rails controller this is my script
def update_by_user
user_skill_selected = UserSkillSelected.create(params[:user_skill_selected][:users])
# check through array if all is valid
if user_skill_selected.all? {|item| item.valid?}
render json: {json_status: save_success}
else
render json: {json_status: save_failed}
end
end
and this is my user_skill_selected_params
def user_skill_selected_params
params.require(:user_skill_selected).permit(:user_id, :subskill_id, :skill_id, :users => [])
end
unfortunately i get an error in my log, the log said
"exception": "#<ActiveModel::ForbiddenAttributesError:ActiveModel::ForbiddenAttributesError>",
after that i try to bulk operations from rails console with using create method with the array value and its work
can anyone solve this... :(
sorry for the bad english
This can be confusing. Your code is passing in params[:user_skill_selected][:users] to the model create method, instead of your user_skill_selected_params strong parameters, which is why you're seeing that error.
Change this line:
user_skill_selected = UserSkillSelected.create(params[:user_skill_selected][:users])
To this:
user_skill_selected = UserSkillSelected.create(user_skill_selected_params)
And it should eliminate this error.

Rails 5 testing controller unfiltered params

I have recently upgraded my application to Rails 5 and when I am testing my controller I am getting the following error:
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash.
My controller code looks like this:
def bid
widget_mode = params.include?(:widget)
if !#auction.published?
redirect_to '/' #go to the homepage
elsif #auction.third_party?
redirect_to #auction.third_party_bidding_url
elsif current_user && current_user.clerk? &&
!#auction.listing? &&
(#auction.items_count == 1 || params["section"] == "auction") &&
!widget_mode
redirect_to action: 'clerk', id: #auction.id, params: params.slice(:item, :section)
else
# Make sure the auction is in firebase
exists = #auction.rt_get('updated_at').body.to_i > 0 rescue false
#auction.queue_realtime_update unless exists
end
end
and my test code looks like this:
test "should redirect to powerclerk if multi item auction and params section = auction" do
sign_in users(:clerk)
a = auctions(:kenwood_dr)
assert a.items.count > 1, "Expected auction to have more than one item"
get :bid, params: {id: a.id, item: a.items.first.id, section: "auction"}
assert_redirected_to "/clerk/1?item=1&section=auction"
end
I tried adding:
params.permit(:item, :section, :id, :controller, :action, :widget)
to the beginning of my bid controller method and that didn't make a difference. Any insight would be appreciated.
This error occurs when calling to_h or to_hash on an instance of ActionController::Parameters that doesn't have any permitted keys (documentation).
Since ActionController::Parameters#slice returns an instance of the same, this code does not give you a hash like it would seem: params.slice(:item, :section).
In most cases you can use permit instead of slice on parameters instances. If you ever want to bypass the safe access whitelisting of ActionController::Parameters you can use permit! and use ActionController::Parameters#slice, or if you want to convert to a hash without sanitization you can use to_unsafe_h.
I ended up solving this by switching:
redirect_to action: 'clerk', id: #auction.id, params: params.slice(:item, :section)
to
redirect_to action: 'clerk', id: #auction.id, params: params.permit(:item, :section)

How to remove special characters from params hash?

I have one application with the following code:
quantity = 3
unit_types = ['MarineTrac','MotoTrac','MarineTrac']
airtime_plan = 'Monthly Airtime Plan'
url = "http://localhost:3000/home/create_units_from_paypal?quantity=#{quantity}&unit_types=#{unit_types}&airtime_plan=#{airtime_plan}"
begin
resp = Net::HTTP.get(URI.parse(URI.encode(url.strip)))
resp = JSON.parse(resp)
puts "resp is: #{resp}"
true
rescue => error
puts "Error: #{error}"
return nil
end
It sends data to my other application via the URL params query string. This is what the controller method of that other application looks like:
def create_units_from_paypal
quantity = params[:quantity]
unit_types = params[:unit_types]
airtime_plan = params[:airtime_plan]
quantity.times do |index|
Unit.create! unit_type_id: UnitType.find_by_name(unit_types[index]),
airtime_plan_id: AirtimePlan.find_by_name(airtime_plan),
activation_state: ACTIVATION_STATES[:activated]
end
respond_to do |format|
format.json { render :json => {:status => "success"}}
end
end
I get this error:
<h1>
NoMethodError
in HomeController#create_units_from_paypal
</h1>
<pre>undefined method `times' for "3":String</pre>
<p><code>Rails.root: /Users/johnmerlino/Documents/github/my_app</code></p>
I tried using both raw and html_safe on the params[:quantity] and other params, but still I get the error. Note I had to use URI.encode(url) because URI.parse(url) returned bad uri probably because of the array of unit_types.
Change:
quantity.times do |index|
To:
quantity.to_i.times do |index|
The reason you are having this problem is because you are treating the params values as the types that you originally tried to send, but they are actually always going to be strings. Converting back to the expected 'type' solves your problem.
However, you have some more fundamental problems. Firstly, you are trying to send an array by simply formatting it to a string. However, this is not the format that the receiving application expects to translate back to an array. Secondly, there is duplication in your request - you don't need to specify a quantity. The length of the array itself is the quantity. A better method would be to build your url like this:
url = 'http://localhost:3000/home/create_units_from_paypal?'
url << URI.escape("airtime_plan=#{airtime_plan}") << "&"
url << unit_types.map{|ut| URI.escape "unit_types[]=#{ut}" }.join('&')
On the receiving side, you can do this:
def create_units_from_paypal
unit_types = params[:unit_types]
airtime_plan = params[:airtime_plan]
quantity = unit_types.try(:length) || 0
#...

Do I always need to add 'if something' in order to avoid 'nil' error?

Do I always need to add if #user in this?
In Pattern 1, it doesn't have if #user so it returns 'nil' error when the user was deleted.
In Pattern 2, it won't return 'nil' error but it's too anoying to add this every single line of these things:(
Isn't there any smart way to solve this kind of 'nil' error?
and I just want to display "[Not Found User]" when the user was deleted.
view/posts/show.html.erb
#Pattern 1
<%= display_nickname(#user.nickname) %>
#Pattern 2
<%= display_nickname(#user.nickname) if #user %>
application_helper.rb
def display_nickname(nickname)
if !nickname.nil?
return nickname
end
"[Not Found User]"
end
In many, but not all, cases you can use the "try" method from ActiveSupport.
foo = Foo.find(1)
foo.bar.try(:some_method)
In the example if bar is nil, some_method will also return nil.
So you could do:
#user.try(:nickname)
You can write your helper like that:
def display_nickname(user)
user.try(:nickname) || "[Not Found User]"
end
what about
def display_nickname(user)
"#{user.try(:nickname)}"
end
or
def display_nickname(user)
user ? user.nickname : ''
end
both will print '' if the user is nil, i'd chose the second

Resources