Rails 5 and RethinkDB Error storing data - ruby-on-rails

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)

Related

How to test that parameter fields are being passed to the controller in Rails 4?

Basically, as my Rails 4.2 applications become more complicated, I sometimes forget to include the appropriate parameters in the user_params strong parameters hash. This leads to information not being saved. For example, I might forget to include the :nickname as per below code.
what's a good way to test that I have included the whitelisted parameters? I don't care if they are nil or some other value, I just need a failing test to remind me to include the parameter.
def user_params
params.require(:user).permit(:id, name, user_nested_attributes: [:nickname, :pet])
end

In Rails, how can a mass-assignment be made to an existing model object without warnings?

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

Getting Started with Rails official Tutorial, ForbiddenAttributesError

I have followed the tutorial letter for letter and I am still getting a forbidden attributes error. I have rails 4.1.4 and ruby 2.1.2. here are my controller methods for a new article
def create
#article = Article.new(params[:article])
if #article.save
redirect_to #article
else
render 'new'
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
I'm sure it's just one singular/plural thing I mistyped or something stupid, but I've been at this one stupid error for more than hour now, so any help is appreciated
Up in the first line, you need to change params[:article] to article_params.
Rails 4+ refuses to initialize an Active Model object unless the attributes passed to it have been explicitly whitelisted. This is a Rails security feature known as strong parameters that was introduced to better protect against mass assignment — "a computer vulnerability where an active record pattern in web application is abused to modify data items that the user should be not normally allowed to access".
params[:article] is an unsanitized hash passed to the create action via a POST request to /articles. It could contain data that sets attributes of the Article model in unintended and unexpected ways. Rails 4+ does you a favor by throwing an exception and not allowing such code to run, rather than leave the onus of security solely on you.
article_params is a call to the private method listed in your example ArticlesController. Notice that it explicitly requires an :article parameter and only permits :title and :text attributes. This prevents a malicious user from authoring a particularly offensive article and then, say, posting it under an innocent individual's name by passing that person's :user_id along with the offensive article.
For a real world example of a mass assignment exploit in Rails, here's an Errata Security article summarizing the Github hack of 2012.

How to stop a user form adding forms to a field?

I have a form that allows a user to update their profile information, but I would like to prevent some information from being changed. I also would like to keep my controller code very simple. In the update action of my Users Controller, I have the following code:
def update
#user = Users.find params[:id]
if #user.update_attributes(params[:user])
flash[:notice] = 'Update successful.'
redirect_to user_path(#user)
else
render :action => :edit
end
end
This is very clean and simple, and I like that. What I don't like, however, is that a user can add a field to the form, with the same name as an attribute, and use it to modify forbidden attributes. Is there a simple way to do this, or do I need to devise a way to do this myself?
One method I was considering was to generate a hash value, using a hash-based message authentication code, of all the form's element names. This message access code would be a hidden value in the form. Then, once the form is submitted, I would calculate the message access code (MAC) again using the names of the parameter Hash's keys. If the two MACs are different, or if the first MAC is missing from the parameter Hash, I would throw an error. I would rather not spend the time implementing this if there was already and easy solution out there.
Thanks.
On your model you can use attr_protected or attr_accessible to blacklist or whitelist attributes when being set via mass assignment (like when a form is submitted).
Rails will prevent mass assignment if you use attr_protected :protectedcolumn (blacklist) or attr_accessible :safecolumn (whitelist) within your model. More information on this topic can be found in the Ruby on Rails Security Guide (Section 6.1)

Rails: Iterate dynamically over params hash to verify they exist

I've got a form with quite a bit of params being passed to the controller for processing. The different 'sets' of params are named in a similar fashion:
setname1_paramname
setname1_paramname2
Now, I need to check one of these 'sets' to verify that all of the fields are submitted. Right now, I'm doing this with a manual If Or style statement:
if setname1_paramname.blank? || setname1_paramname2.blank? || ...etc
#object.errors.add_to_base("All setname1 fields are required.").
render :action => 'new'
return false
end
Is there way to programmatically loop over these params, and add them to the #object errors?
Thanks!
Since it sounds like you have a ton of params and also seems like you need to be able to do checks on groups of params, maybe something like this would be useful? Basically, iterate over the params hash, and use regular expressions to target sets of params. Then, inside the loop, you can do any sort of validations:
params.each do |key, value|
# target groups using regular expressions
if (key.to_s[/setname1.*/])
# whatever logic you need for params that start with 'setname1'
if param[key].blank?
#object.errors.add_to_base("All setname1 fields are required.").
end
end
end
If the names are arbitrary and of your own choosing, you could make virtual attributes for them in your model and let Rails handle the presence checking.
class SomeModel < ActiveRecord::Base
VIRTUAL_ATTRIBUTES = [:billing_address, :billing_state, :something_else]
attr_accessor *VIRTUAL_ATTRIBUTES
validates_presence_of *VIRTUAL_ATTRIBUTES
…
end
Is there a reason you wouldn't just store this information in a model, even if temporarily, and then just use rails validations for your information?
I'm rusty but I assume that even if the value is blank the param will still be returned in the params hash as long as it is coming from a form element, yes? Could you just iterate through the params hash and keep a counter of how many values are not blank and then compare the length of the params hash to the counter. If the counter is short then you have blank parameters and can handle the error that way without having to hardcode checks for each individual parameter, yes?
If what you need is a multi-step form as I suspect, you may find the Railscast on Multistep Forms to be useful

Resources