Rails 3.2 POST with AJAX creating MassAssignmentSecurity::Error - ruby-on-rails

I'm a bit of a nube, and I am trying to piggyback on bokmann's rails3_fullcalendar to create a calendar app in rails 3.2, but when I try to create an event in my app I get this error:
ActiveModel::MassAssignmentSecurity::Error in EventsController#create
Can't mass-assign protected attributes: title, description, starts_at(1i), starts_at(2i),
starts_at(3i), starts_at(4i), starts_at(5i), ends_at(1i), ends_at(2i), ends_at(3i), ends_at(4i),
ends_at(5i), all_day
{"utf8"=>"✓",
"authenticity_token"=>"bq3ZUXLm4lYbja9FUafbroFF2Zwt8iMw6GWfvoRuPLA=",
"event"=>{"title"=>"sddfsdf",
"description"=>"df",
"starts_at(1i)"=>"2012",
"starts_at(2i)"=>"6",
"commit"=>"Create Event"}
The solution looks like it should be this but passing the AUTH_TOKEN with the AJAX POSTs (which it is sending) but it is still not working.
Any ideas?

The answer to your specific question is below, but a better answer is to look at the new version of that demo. Since the demo you're looking at, I have recreated the demo showing how to do this in Rails 3.2 with the fullcalendar JavaScript and css as an asset gem:
https://github.com/bokmann/fullcalendar_assets
Sometime recently (Rails 3.2?) the defaults for protection against mass assignment were changed... you now need to specifically allow the attributes that you want to allow mass assignment.
http://guides.rubyonrails.org/security.html#mass-assignment
In the event model, add a line that looks like this:
attr_accessible :title, :description, :starts_at, :ends_at, :all_day

If you get this Exception, you should already be authenticated, so the Auth_token is not your problem.
Rails has since version 3.2.3 a default to protect against mass-assignments.
You need to explicitly allow them in the model. That is why older code from third parties will fail. Change the model to:
class Event
..
attr_accessible :title, :description, starts_at ...
end
But do not include things like user_id into the list of allowed attributes, this way you prevent somebody who is only allowed to change her own events to reconnect the event that it will then to belong to another user.
See also the Rails Guide:
Security Guide, Mass assignment

The fullcalendar app appears to be created before config.active_record.whitelist_attributes = true became a rails default.
In your Event model, do you have a line like
attr_accessible :title, :description etc.?

Related

ActiveAdmin Changing Links to Name Instead of ID

For one of my models in ActiveAdmin, it is changing the URLs to use the name instead of ID.
For example: http://localhost:3000/admin/product/PH instead of http://localhost:3000/admin/product/1
I don't understand why it's doing that since all of the other models are working correctly (using ID).
This model has no models/product.rb file.
# app/admin/product.rb
ActiveAdmin.register Product do
permit_params :name,
:amount,
:description
end
I checked the documentation and didn't see anything that looks like it would make this happen.
Also, all of the other SO posts I've seen related to name and URL seem to be trying to do the opposite - changing the default route to use name (instead of ID).
Late reply, but I just met the same problem.
It was due to slug. I just remove slug from my model and it worked.
Hope it could help someone.

Ruby on rails scaffold model validation questions

I am trying to follow a ruby on rails scaffold example.
I am using ruby version: 2.1.5 with rails version : 4.1.8
I have used this command:
rails generate scaffold User name:string email:string
This worked fine - I can run the example which shows crud functionality to my generated scaffold. The examples I have been following advise to look at the model file generated. The ones in the examples seemed to have a value called attr_accessible - but for me this was not generated - I do not know why - it seems to be quite useful so you can easily see what is inside your model? My model looks like this:
class User < ActiveRecord::Base
end
I altered it to look like this :
class User < ActiveRecord::Base
attr_accessible :name, :email
validates :name, :presence=>true
end
and when I now visit localhost/users I get the error:
Can somebody please tell me how a generated model can be created with this attr_accessible line, and how I can add an example of validation to the model.
Rails 4 doesn't use attr_accessible; it uses Strong Parameters.
They both serve as a guard for mass assignment of params, often times used during form submissions.
The scaffold doesn't support automatically setting strong params as far as I'm aware, in part because people implement strong params white listing very differently.
A couple more links on Strong Params
How is attr_accessible used in Rails 4?
https://github.com/rails/strong_parameters
https://github.com/elabs/pundit#strong-parameters <= I strongly recommend this gem
To me this suggests whatever guide you're following is out of date.
I think the problem is that the scaffolding that you have used is not compatible with how Rails works in later versions. In earlier versions of Rails, attr_accessible was used for preventing security problems related to mass assignment. In later versions, the countermeasure changed and moved to the controller instead of the model.
If you still want to use the attr_accessible macro, you can add gem 'protected_attributes' to your Gemfile and install with bundler.
You shouldn't add them in the model.
The stuff you wanna access goes into the controller, like
def index
#users = User.all
end
def show
#user = User.find(params[id])
end
...
private
def user_params
# It's mandatory to specify the nested attributes that should be whitelisted.
# If you use `permit` with just the key that points to the nested attributes hash,
# it will return an empty hash.
params.require(:user).permit(:name, :mail)
end
so you can use them afterwards in your views.
e.g. in app/views/users/show...
<h1>#user.name</h1>
<p>#user.email</p>

Redundant security by deleting protected params?

In Rails 3, we can define the accessible attributes:
attr_accessible :rating, :review
In this model, there is additional user_id which is protected to prevent forgery/hacking. This value is assigned in the controller:
#review.user_id = current_user.id
If I use Firebug to manually include the user_id, it will be part of the params[:review], but of course since user_id is not defined in the attr_accessible, it wouldn't get saved into the database. Such case is rather secure.
Question 1
I read in Rails 3 In Action book, Yehuda Katz included .delete method to delete unauthorized params before further action is performed: params[:review].delete(:user_id). Should I include this as well to further secure my app, or just ignore this step?
Question 2
If I should include the method above, I would like to have something like .delete_all_except to just strip it to the allowed attributes in the params. How do I do that?
Thanks.
If enabled, Rails 3.2 will through an exception if additional mass-assignment params are sent to the model
config/application.rb
config.active_record.whitelist_attributes = true
Rather than deleting out parameters you don't want, I recommend only accepting parameters you do want:
#user.update_attributes params[:user].slice(:rating, :review)
This will only return the user params you allow.
note: in Rails 4 (coming soonish), this behavior is implemented with a DSL named strong-parameters. You can install this gem in Rails 3.2 to implement now:
#user.update_attributes params.require(:user).permit(:rating, :review)

Rails belongs_to and has_many relationships problems

I'm pretty new to rails, building my first 'real' app and struggling to understand how to make relationships work properly.
I have a Quiz model and and Icon model. Each Quiz belongs_to an Icon, an Icon has_many Quizzes. (think of an icon as a category).
On my "new/edit" Quiz forms I want a select box to choose the correct Icon. At the moment I have...
<%= collection_select(:quiz, :icon_id, Icon.all, :id, :title, :prompt => true) %>
And in my Quiz controller create action I have...
def create
#icon = Icon.find(params[:quiz][:icon_id])
#quiz = #icon.quizzes.build(params[:quiz])
if #quiz.save
flash[:success] = "New quiz created successfully!"
redirect_to #quiz
else
render 'new'
end
end
When I submit the form I get a
Can't mass-assign protected attributes: icon_id
error which I understand as icon_id isn't assigned as being attr_accessible in the model.
I could either make it accessible as there is no real security risk around this or I could remove the icon_id from the quiz hash before passing to the build method but both these options don't seem like the right way to do things.
What is the right way to do this?
Thanks!
Just put
attr_accessible :icon_id
in your Quiz model.
From the Ruby on rails api: attr_accessible: Specifies a white list of model attributes that can be set via mass-assignment.
TL;DR: Rails has a feature called mass assignment, which is what you are doing when you pass in that params[:quiz] hash. You need to specify attr_accessible for any attributes you wish to update using mass assignment.
A quick history lesson:
It used to be that all attributes were mass assignable by default, so your code would have worked just fine.
A number of months ago, there was a highly publicized episode at github where somebody was able to exploit this feature by constructing a post body with something to the effect of user[:admin] = true. This effectively gave the user admin access, because the application didn't prevent just anybody from setting admin = true. There was a way to prevent this, but the developers missed it.
The response by Rails to this was to make all attributes protected by default, forcing the developer to explicitly specify any fields available to be updated via mass assignment. I believe this was in the 3.2.3 release.

Dynamic scope for accessing Model Attributes

I'm currently using the mass assignment security baked into rails 3 to scope what level of users can update about their model. For example this code allows me to protect attributes based on the user level.
class Customer
attr_accessor :name, :credit_rating
attr_accessible :name
attr_accessible :name, :credit_rating, :as => :admin
end
I would like to be able to use this same idea for which attributes appear when I do a find. For example I would like to be able to say
Customer.all.as(:admin)
and get back the credit rating. Compare this to doing
Customer.all
and getting back all the attributes except the credit_rating
Is this something rails supports and I've missed?
attr_accessible is used to filter incoming attributes on mass assignment. This is a convenience method created so that a developer does not need to manually clean the incoming hash of params, something he does not control.
When displaying information a developer is in full control of what he/she desires to show, so there seems to be no reason to limit the read functionality.
However, rails allows you to "select" the attributes you desire in a query: see http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields
You could easily create a scope with the name admin that would limit the selected values.
If you do not desire to have the full models, but only the values, you could use the generated sql. e:g.
ActiveRecord::Base.connection.select_values(Customer.select('name').to_sql)

Resources