rails 5 ForbiddenAttributesError on bulk operations - ruby-on-rails

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.

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.

Error while iterating through params

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}]".

Printing error when using PARAMS in Rails

For my API in RAILS I have programmed a code that basically does the following.
class Api::V1::NameController < ApplicationController
skip_before_filter :verify_authenticity_token
def index
end
def create
# Loading data
data_1_W = params[:data1]
data_2_W = params[:data2]
while len > i
# -Here I do some calculations with data_1_W and data_2_W.
# Its not important to show the code here
end
# -Organizing outputs to obtain only one JSON-
# Its not important to show the code here
# Finally HTTP responses
if check_error == 1
render status: 200, json: {
message: "Succesful data calculation",
data_output: response_hash
}.to_json
end
end
end
To test that everything is working I use the cURL command. I notice that loading the data could be a problem and therefore the code would break.
I want to tell the user that it was an error loading the data for some reason (HTTP response), but I don't know where to put it. If I put and else under my success status it would not print it because the code breaks just starting (instead of sending the correct name - d '#data.json' of the data in cURL I send -d '#dat.json').
The data I am loading is a JSON data {"data1":[{"name1":"value1"},{"name2":number2}...],"data2":[{"name1":"value1"},{"name2":number2...}]}. (This data has 70080 rows with 2 columns if we see it as a table, which I divided into two in my CODE for calculations purposes data_1_W and data_2_W)
Could anyone help me where to put it? more or less like this:
render status: 500, json: {
message: "Error loading the data",
}.to_json
Put it in a rescue block around the code that throws the error.
E.g.
def func
# code that raises exception
rescue SomeException => e
# render 422
end
Since you are working in Rails I'd recommend going the rails way. This means that I would create some kind of service and initialize it in the create action.
Now, within the service you do all you funky stuff (which also allows you to clean this controller and make i look prettier) and the moment a condition is not fulfilled in that service return false. So...
# controllers/api/v1/name_controller.rb
...
def create
meaningful_variable_name = YourFunkyService.new(args)
if meaningful_variable_name.perform # since you are in create then I assume you're creating some kind of resource
#do something
else
render json: {
error: "Your error",
status: error_code, # I don't think you want to return 500. Since you're the one handling it
}
end
end
# services/api/v1/your_funky_service.rb
class Api::V1::YourFunkyService
def initiliaze(params)
#params = params
end
def perfom #call it save if you wish
....
return false if check_error == 1
end
end

Rails 4 custom json errors

I am using Rails 4 i am trying to set an api and i have a services controller where i def some methods like this:
def articles_stores
#article = Store.find(params[:id])
if #article.nil?
render :json => {:error_msg => "Record not found",:error_code => 404,:success => false}
else
render json: {article: #article.as_json({except: [:updated_at,:created_at]}),success: true}
end
end
But for some reason it is not rendering the error the else part works fine y also have all the necessary routes
Any help will be appreciated
#article.nil? will never be true if the article does not exist: Store.find(params[:id]) will already raise an exception if the record does not exist, and this than gets handled by rails automatically as a 404. If you want to return nil, use something like this:
Store.where(id: 10).first
# old, deprecated way:
Store.find_by_id(10)
Also see here.

Simple Mongoid Validation for create! - how to display error messages

I'm using Rails 3 with mongoid 2 and have a simple question regarding mongoid validation.
if #forum.topics.create!(name: params[:topic][:name])
# success, do something
else
#should handle errors but doesn't
render 'new'
end
If I use the .create! method, it runs validations on a mongoid model class correctly, but it is not getting to the else block to display the error. Instead it returns a rails error page saying...
Mongoid::Errors::Validations in TopicsController#create
Validation failed - Name can't be blank.
That's good, but how do I display that in a view instead of getting an ugly rails error message page?
Try this way:
new_topic = #forum.topics.new(name: params[:topic][:name])
if new_topic.save
# success, do something
else
render 'new', errors: new_topic.errors.full_messages
end
with this way you will have the local variable errors which is a Hash formated like following:
new_topic.errors.full_messages # => ["\"Name\" can't be blank"]
you can rescue the Mongoid::Errors::Validations and use it's instance method to get the errors
new_topic = #forum.topics.new(name: params[:topic][:name])
new_topic.create!
rescue Mongoid::Errors::Validations => e
summary = e.summary
problem = e.problem
res = e.resolution
using the above error messages you can display the error
Documentaion link
https://docs.mongodb.com/mongoid/6.2/api/Mongoid/Errors/Validations.html

Resources