I am currently trying to implement raising an error when unpermitted parameters are posted in my RoR back-end. I included
config.action_controller.action_on_unpermitted_parameters = :raise
in my development.rb configuration. Now, for example I have in one of my controllers:
def apiary_params
params.require(:apiary).permit(:name, :municipality, :prefecture, :latitude, :longitude, :numberofbeehives, :notes)
end
If I now try posting another parameter lets say "apiary[asdf]" then an internal server error is raised correctly. However if I try posting a random "asdf" param not in the apiary hash, then the request is handled without an error. Does that mean that the random "asdf" and whatever other parameter not in the apiary is permitted? How can I fix that?
No, those extra parameters are not permitted - they're silently discarded.
You're only calling permit on params.require(:apiary), that is, params[:apiary], so only extra attributes inside that hash will raise an exception.
As soon as you make that params.require call, then all other params submitted become irrelevant for the return value of this method. You're only dealing with data inside that params[:apiary] hash, and that is what will be returned.
Related
How can i use query parameter as a strong parameter.
This is my POST /tag method called by frontend to search posts.
def tag
if params[:category] == 'Shop'
render json: ShopPostPopulator.new(params[:search]).run
else
render json: Part.search(params[:search])
end
end
If i want to use strong parameter instead of 'params[:search]', how should I do it.
ActionController::Parameters is really just a hash like object and "strong parameters" is really just the equivalent of using Hash#slice to only allow a whitelist of attributes through. Which protects against mass assignment attacks. Beginners and often experienced Rails devs. seem to think that it magically filters and cleans the parameters. It doesn't - it just prevents you from getting a mass injection attack out of ignorance, stupidy or laziness.
Whitelisting is only needed if you are assigning a hash of parameters to a model:
User.update(
params.permit(:email, :password)
)
In this case it prevents a malicious user from for example passing role=superadmin or id=1 (as the first user is often the admin). If you are just assigning a single attribute from the params hash you don't need to use strong attributes. The major difference introduced back in 2012 is that whitelisting became manditory as an error is raised if you pass a ActionController::Parameters object without the #permitted = true attribute to .new, .update, .create and the other methods that spawn or update records.
If you want to though you can use ActionController::Parameters#permit to ensure that the parameter is a simple scalar type (not a hash or array):
params.permit(:search).fetch(:search, nil)
If search is an optional parameter with nested keys you can whitelist it like so:
params.fetch(:search, {}).permit(:foo, :bar)
You can also make the parameter required so that a ActionController::ParameterMissing exception is raised if its missing:
params.require(:search).permit(:foo, :bar)
Which is what you do 99% of the time in Rails since it bails early if we can't do anything meaning with the request.
I have a factor controller which takes factor values for two different types of factors
Primary Factor
Secondary Factor
And I pass them as params as follows:
class FactorController < AdminController
def create
if primary_factor_params ## LINE 5
do something
elsif secondary_factor_params
do something else
end
end
def primary_factor_params
params.require(:primary).permit(:user_id, ## LINE 70
:primary_factors)
end
def secondary_factor_params
params.require(:secondary).permit(:user_id,
:secondary_factors)
end
end
But in the above whenever I try to pass a secondary_factor I get the following error:
ActionController::ParameterMissing (param is missing or the value is empty: primary):
app/controllers/factors_controller.rb:70:in `primary_factor_params' app/controllers/api/v1/admin/factors_controller.rb:5:in `create'
So to me it seems that this error is coming up because I didn't have any values for primary_factor_params in this condition and that's way it throws the error because of the first if condition.
I've tried:
primary_factor_params.exists?
primary_factor_params.has_key?(:primary_factors)
....
But all of them throw the same error since primary_factor_params doesn't exist. Is there a way to test this without throwing an error for missing params?
The problem is this line params.require(:primary) saying that the parameter is required, so attempting to do like params.require(:primary).exists? wont help you if you do not have a :primary param at all because the require already failed.
You need to check its existance on params itself. For example params.has_key?(:primary).
Dependening on your use case, you might also use params.permit(:primary) directly on params as well. See the API docs for detailed information on how ActionController::Parameters (the class for params) can be used.
http://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-permit
you can check your params existence in your case by params[:primary].present?
I think this is the easiest way
Simple Blog app in Rails / Rethinkdb / nobrainer gem
model
class Post
include NoBrainer::Document
include NoBrainer::Document::Timestamps
field :title, :type => String
field :body, :type => Text
controller
def post_params
params.require(:post).permit(:title, :body)
end
works fine with Rails 4 same in Rails 5 error:
Some idea ??
To assign attributes, please pass a hash instead of `ActionController::Parameters'
This is an issue with NoBrainer. It's already been fixed in the current git HEAD release, and will be included in the next update release.
Do not simply bypass Strong Parameters by converting post_params to a hash as previously suggested; this will allow any user to submit any form fields they wish, and your application will blindly accept it. This is a huge security issue, as any attacker can now pass arbitrary column data (like, say, "is_admin = 1") and your app will cheerfully accept them with no qualms.
If you ever convert parameters to a hash, you are making the wrong decision. You should never be passing raw params into a model from a controller. Strong Parameters is there to protect you. If the permit and require white lists aren't working, Rails or your ORM is broken. Stop, figure out which one is broken, and report it to the appropriate project.
According to your error message To assign attributes, please pass a hash instead of 'ActionController::Parameters' I assume somewhere in your app have a code:
Post.create(post_params)
Convert to a hash with the to_h method:
Post.create(post_params.to_h)
In a Rails application it's possible to assign some values from params to an existing model object, like this:
model.attributes = params
This would obviously return a ForbiddenAttributesError but that can be avoided like this:
model.attributes = params.permit(:a, :b, :c)
However, although that works, it still outputs a message to the console if params contains keys that are not mentioned in the call to permit:
Unpermitted parameters: d, e, f
The warning is pointless because it's already known that params contains additional keys and permit is being used to select the required subset. It can be avoided by doing
model.attributes = params.slice(:a, :b, :c).permit!
Is there a more appropriate way to do this assignment that does not require having to slice the hash first?
The warning is pointless because it's already known that params contains additional keys and permit is being used to select the required subset.
You mistake the purpose of this warning. It is very valuable when you debug why your form doesn't update this new field you added just today. With the warning, looking at the server log you can quickly find out that you forgot to update strong_params filtering.
Also, the warning will only be shown in dev/test environments. It won't appear in production.
But suppose you really hate that warning. In which case you can do this in your app config:
# possible values: :raise, :log
config.action_controller.action_on_unpermitted_parameters = false
BTW, your code is a bit unorthodox. The common way is to keep the filtering code in one method and call it from both create/update (and whereever else you need it)
def update
#product = ...
if #product.update_attributes(product_params)
...
else
...
end
end
private
def product_params
params.require(:product).permit(:a, :b, :c)
end
Faced a strange problem or bug.
i have a route with strong parameters method:
def st_params
params.permit([:id, logs: [], metric_ids: []])
end
Then i call it with, for example, rspec:
post some_path(format:json, metric_ids:[ [1,0,1], [5,1,4] ])
And when i call a st_params method there is no metric_ids param and i have got message in logs: Unpermitted parameters: metric_ids
But if i change st_params method like this:
def st_params
p = params.permit([:id, logs: [], metric_ids: []])
p[:metric_ids] = params[:metric_ids]
# or just p = params.permit!
p
end
Now, everything works fine in browser, but it looks strange.
But in rspec i have received nil value for metric_ids in any case :( I have not found any information about the problem. Maybe someone here may help me.
Thanks in advance.
2 things that may be causing your trouble here:
1) The bang method permit! is for accepting an entire hash of parameters and it does not take any arguments. I also am unsure if permit! can be called on the entire params hash, the documentation is unclear on this.
2) Your use of array notation may be causeing the params hash some confusion. (It also may be acceptable, but looks a little unorthodox compared to what I'm used to seeing.) I would write your st_params as
def st_params
params.permit(:id, :log, :metric_ids)
end
Also, a permit argument like metric_ids: [] as you have written will whitelist any parameters nested inside of params[:metric_ids], based on the way you are passing data to this hash above, I do not think this is your intended usage. It appears that you are storing an array at this level of the hash and there is no further complexity, so no need to whitelist params beyond this scope.
Hope this helps!
I was facing same problem. Appending as: :json to post solved the problem for me.
Ref: https://github.com/rspec/rspec-rails/issues/1700#issuecomment-304411233