How to retrieve all attributes from params without using a nested hash? - ruby-on-rails

I am currently in the process of making my first iphone app with a friend of mine. He is coding the front end while I am doing the back end in Rails. The thing is now that he is trying to send necessary attributes to me with a post request but without the use of a nested hash, which means that that all attributes will be directly put in params and not in a "subhash". So more specifically what I want to do is be able to retrieve all these attributes with perhaps some params method. I know that params by default contains other info which for me is not relevant such as params[:controller] etc.. I have named all attributes the same as the model attributes so I think it should be possible to pass them along easily, at least this was possible in php so I kind of hope that Rails has an easy way to do it as well.
So for example instead of using User.new(params[:user]) in the controller I have the user attributes not in the nested hash params[:user] but in params directly, so how can I get all of them at once? and put them inside User.new()?

I found the solution to my problem. I had missed to add the attr_accessible to my model which was what initially returned the error when I tried to run code like: User.new(params) having been passed multiple attributes with the post request.
The solution was very simple, maybe too simple, but since this is my first real application in Rails I feel that it might be helpful for other newbies with similar problems.

If you would like to just pass a more limited version of params to new, you should be able to do something like the following:
params = { item1: 'value1', item2: 'value2', item3: 'value3' }
params.delete(:item2)
params # will now be {:item1=>"value1", :item3=>"value3"}
Also see this for an explanation of using except that you mention in your comment. An example of except is something like:
params.except(:ssn, :controller, :action, :middle_name)

You can fetch the available attributes from a newly created object with attribute_names method. So in this special example:
u = User.create
u.attributes = params.reject { |key,value| !u.attribute_names.include?(key)
u.save

Related

Unpermitted parameters issue Ruby on Rails 5

I'm currently trying to understand how permitted parameters works in ruby.
Usually, in my_model.rb I have:
has_many: some_other_model
*
*
*
def my_model_params
params.require(:my_model).permit( :column1, some_other_model_attributes %i[other_column1])
etc...
and in the update function
my_object.update_attributes(my_model_params)
with a well formatted json which has some my_model root, and some_other_model_attributes as a child (array) with values.
My problem is I receive a json like this one
However the different arrays inside (such as codification, general_information) do contain attributes of the mission (general_information contains reference that is a column in the mission table) but there isn't any column named codification, or relation to a codification_attributes.
So, when I add :
general_information: %i[reference] in the permitted params, it says unknown attribute 'general_information' for Mission.
If not, no error are raised but in the log I can see unpermitted_parameter: general_information. And my object is not updated.
Finally if I reject it, there is no more unpermitted_parameter: general_information in the log but my object is not updated either.
I tried to set config.action_controller.action_on_unpermitted_parameters to false in my development config, it did nothing and it's probably a bad idea for production environment anyway.
The use of .permit! (even if it works) is currently not an option. And even though I think the json needs to be re-formatted it'd be better to find an other solution.
Thanks for the help.
unpermitted_parameter: ... in logs in not a problem which you need to fix, it's just an info.
How it works - you just permit needed parameters, you may think about them as a hash. Unpermitted parameters will not go into the model even if they are present in params. It means when you call
my_object.update_attributes(my_model_params)
it works like
my_object.update_attributes(column1: value_for_column1_from_params)
Keys in params should be named exactly as columns in the model, otherwise you need to prepare params somehow before create/update

Rails 4 Params Permit array of objects with arrays as values

I have a check_box_tag that returns me a permission object that I can't seem to permit.
I have checked on StackOverflow and tried a few things but since I am new to coding and params I can't get to make it work.
The params look like this:
"product_builder_permissions"=>[{"1"=>["1"], "2"=>["1"], "6"=>["42", "59"]}]
with the key of the nested hash being the id of the product builder and the values in the array the object id to which those builders have access to.
If I change a bit my HTML and get one key for each builder, I am able to whitelist with something such as params.permit(
product_builder_permissions1: [])
params.permit(
product_builder_permissions1: [])
etc.
which is inefficient.
I am trying to work with something like params.permit(product_builder_permissions:[0]) I only whitelist the key and value at the first level but not what's nested since I get
{"product_builder_permissions"=>[{}]}
I also tried something like
params.permit(product_builder_permissions:[0][:builder_id.to_s.to_i, :maker_id.to_s.to_i]) to no avail.
Thanks in advance.
Given that you're not doing mass assignment, I suggest you skip the heartache of strong parameters and just manipulate the parameters directly.

Should we use strong params when we update only one attribute?

I'm working on a Rails app and I have several actions( #delete_later, #ban_later and so on) where I only set one attribute from the request parameter( specifically, a reason field for doing that action).
I was wondering if it is ok to do it like this:
def ban_later
#object.reason = params[:object][:reason]
#object.save
end
Or is it a best practice to use strong params even in this situation?
def ban_later
#object.reason = object_params[:reason]
#object.save
end
private
def object_params
params.require(:object).permit(:permitted_1, :permitted_2, :reason)
end
Which of these solutions is the best one? If none of them is, then what's the best solution to my problem?
Later Edit:
The #ban_later, #delete_later actions can indeed set a flag column status but that can be done without receiving it's value from the params hash. Since you will only set one status per method you can simply set the status "pending_delete" when you are in #delete_later and "pending_ban" when you are in #ban_later.
Later Later Edit
Why use #save and not update_attributes directly? Let's say you need to have a if #object.save statement. On the false branch( object not saved) you might still want to render a view where the contents of that #object are used.
First one saves computation.
Second one checks for existence of :object sub-hash, which I think is good for fault-tolerance.
I initially would pick the 1st, but after some thought I liked the second one more.
The simplest answer is that if you only use one parameter in params, and do not pass it to a multi attribute setter like model#create then you don't have to use strong_parameters to get a secure solution.
However, I expect that it is unlikely that this is the case for the whole controller. Where the ban_later method only needs one parameter, other controller methods will need more. In this case the question becomes: "do you want to handle params differently for ban_later to how you use it for the other controller methods?".
Also can you be sure that the functionality will not change, and that when you change the functionality, that you'll remember to change the way params is handled.
Therefore, I would use strong_parameters because it means:
parameters are handled consistently across all methods in the controller.
changes to methods are less likely to expose vulnerabilities as functionality changes.
If you're updating a single attribute, why don't you use the update_attributes method? (update_attribute doesn't invoke validation)
def ban_later
#object.update_attributes reason: params(:reason)
end
private
def params params
params = %i(:permitted_1, :permitted_2, :permitted_3) unless params
params.require(:object).permit params
end
In light of the comments by ReggieB, you could also use the update option:
def ban_later
#object.update reason: params(:reason)
end
As mentioned, Reggie and the other answers explain the schematics of how this works best (IE with mass-assignment etc). Above is actionable code which you're free to use.
The bottom line here is that if you want to keep your application versatile (IE having ultimate extensibility wherever you need), you'll need to adhere to the strong params setup.
The other answers outline how that setup works, and how its functionality is different dependent on what you need.
I have included a trick to make it so you only accept specific params in your params method. I've not tested it extensively, so we may have to refactor it to get the required result.
After strong parameters check why not just update the object? Its just a standart workflow. (Please tell me if there are any reasons not to do that in your situation)
def ban_later
#object.update(object_params)
# dont forget validation check
end
private
def object_params
params.require(:object).permit(:permitted_1, :permitted_2, :reason)
end
In this case it'd be much easier to add more updateble fields.

ruby on rails iterating params

I have a client that is sending params such as age, gender, name and so on.
I need to retrieve data from the table based on the params, but first I need to check for the presence of the param(to avoid a null param and therefore an empty result). The params are working as filters, so they can be triggered or they can be left blanck.
What I am doing right now is
#retieve = Student.all
unless params[:age].nil?
#retrieve = #retrieve.where(age: params[:age])
end
unless params[:gender].nil?
#retrieve = #retrieve.where(gender: params[:gender])
end
and so on for every param I receive. This way I check if the filter has been selected, and if it has I use the selection as a parameter for the query
It works, but as Ruby is known for the DRY statement, I am pretty sure someone out there knows a better way for putting this and to make this flexible.
Thank you for whatever answer or suggestion you will provide!
This will work best if all of these filters were in a subhash of params that you can iterate over without including unwanted parameters (eg the :action and :controller parameters that rails adds)
Once you've done that you could do
(params[:filters] || {}).inject(Student.all) do |scope, (key, value)|
scope.where(key => value)
end
There's a few ways to do this sort of thing and you have options for how far you want to go at this stage.
Two big things I'd consider -
1) Make nice scopes that allow you to send a param and ignore it if it's nil. That way you can just append another scope for each param from the form and it will be ignored without using if or unless
2) Move the search into a separate class (a concern) to keep your controller clean.
Here's a blog post that talks about some of the concepts (too much to post in this answer). There is lots of info on the web about this, I searched on the web under "rails search filter params concern" to get an example for you.
http://www.justinweiss.com/blog/2014/02/17/search-and-filter-rails-models-without-bloating-your-controller/

Is it bad practice to constantize parameters submitted through the browser?

I've got a single-table-inheritance setup where I have a single Controller (I felt having multiple would be duplicative). However, for some methods, I'd like to call into the subclasses of the models. I figured I could have the browser send a parameter that I'd write a case statement against. Something like:
case #model[:type]
when "A"
#results = Subclass1.search(params[:term])
when "B"
#results = Subclass2.search(params[:term])
...
end
Alternatively though, I learned that Ruby, in all it's trickery can create a model out of a string. Something like:
#results = params[:model].constantize.search(params[:term])
My question: is this a bad practice? I can imagine someone sneaky could craft a request that would get me to form an arbitrary internal object.. but I could confirm that the object is a subclass of the thing I want..
When doing this, i like to refactor it with case, just to be very clear about my allowed inputs:
#results = case params[:model]
when 'page' then Page
when 'post' then Post
else raise 'finger'
end.search(params[:term])
If you have a whitelist of objects that you check it against before you do it, then you should be ok. You just always want to make sure you are santizing and validating input coming from external sources very throughly to protect yourself.
This snippet uses Ick's maybe for simplicity, but write it as you feel comfortable, the point is simply to use a hash:
#results = {"A" => Subclass1, "B" => Subclass2}[params[:model]].maybe.search(params[:term])

Resources