Getting Started with Rails official Tutorial, ForbiddenAttributesError - ruby-on-rails

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.

Related

Rails 5 and RethinkDB Error storing data

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)

Explanation of User.new in Ruby on Rails? (From Michael Hartl's tutorial)

I have searched everywhere to try to find an explanation of how this works/what its purpose is, but I cant find anything helpful.
I am doing Michael Hartl's tutorial, and my question is mainly about the two actions: 'new' and 'create'.
The new action has the following:
def new
#user = User.new
end
In the view corresponding to the 'new' action, there is a form_for helper, where users can type in their attributes and hit submit. As expected, the beginning of the form_for helper looks like this:
form_for(#user)
However here is where I am stumped... In the create action, there is the following code:
def create
#user = User.new(user_params)
#user_params is a function we defined which simply returns the permitted params from the user.
What is the purpose of #user = User.new in the 'new' action? What does User.new even accomplish? I am assuming that the instance variable #user is necessary to pass to the form, but in that case, why do we have to redeclare an #user isntance variable in 'create'? Isn't it sufficient to have only #user = User.new(user_params) in our 'create' action? Is the User.new somehow necessary to make the form function properly?
I am mainly just trying to figure out what #user = User.new accomplishes in our 'new' action and its corresponding 'new' view (with the form), and why it is necessary when we have a 'create' action which actually CREATES the object. ANY help is SO GREATLY APPRECIATED. Thank you all for always doing your best to explain. Thank you ahead of time to anyone who answers this.
The new and create are different actions. New is called when you get the new route. Create is called when you post to the new route. So, you have to create the user in new so they're available in the form. You have to create the user with the form contents in create so you can save it to the database.
You can't assume that the request to new will go to the same rails instance as the request to create. It's common to run multiple instances of your app behind a proxy.
It's called object orientated programming
HTTP
In Ruby, each variable you define is an object. These objects are then manipulated throughout each instance of the app.
In traditional (stateful) applications, your computer is able to store a number of objects in memory, and since your application is always in state, you'll be able to manipulate them from a single invocation.
In HTTP (stateless) applications, you have to rebuild the objects with each call. Because your application doesn't retain state (memory) between each request, you have to build the objects again.
This is why Rails "variables" are called with a class function on the model (class): User.find ...
--
Thus, when using the following:
#app/controllers/your_controller.rb
class YourController < ApplicationController
def new
#user = User.new #-> invokes a new user object
end
def create
#user = User.new user_params #-> invokes a new user object & populates with your params
#user.save #-> "saves" the new record
end
def show
#user = User.find params[:id] #-> stateless means you have to rebuild the object again
end
end
... what you're doing is rebuilding the object each time your actions are invoked.
This is one of the pitfalls of using HTTP - your server is "dumb" and cannot retain state between requests. Although Rails does a great job at making it a seamless process, it can be difficult if you haven't got your head around it yet.
Most generally, users enter data and we programmer-types traditionally store it in a relational database.
This creates an "impedance" between a relational model (i.e., tables and rows) and an object-oriented one (roughly, classes and instances).
ORMs like ActiveRecord help abstract much of this tedium, and in this way model instances--such as those we're creating in controller actions--serve as helpful containers for data.
This lets us easily represent models in views when gathering user input, and bind inputs to model attributes when persisting it (basic CRUD).
The separate controller actions merely represent these two steps in the process, as any Web-based app ultimately speaks HTTP.
This is really the whole benefit and genesis of Rails and similar MVC frameworks, born in a time of relational databases and server-side rendering. (Though they are increasingly coping with and adapting to an environment that now includes document/object-oriented databases and client-scripted front-ends.)

Ruby - How to define params for require()?

questions_controller.rb
def index
#questions = Question.all(app_params)
end
private
def app_params
params.require(:questions).permit(:question, :answer)
end
end
question.rb
class Question < ActiveRecord::Base
end
I am completely new to ruby-on-rails. I was following a guide and it said I should take care of some "loopholes" or "security issues" and it used attr_accessible, but on Rails 4, they suggest strong parameters, so now I'm trying to use them. I'm confused on how to define the :questions params, because I'm currently getting an error saying that :questions param is not found.
:questions is pretty much something that I will define myself as the web developer.
So for example, I will define questions = "How are you?", "What is your name?". I'm basically starting very simply. I want questions that I have created to be displayed on my webpage. Ultimately, I plan to make a website what is basically a list of questions and, with answer options. After the user clicks "submit" I want to store the information into my database.
Am I supposed to even be requiring this as a param? I'm completely lost..
Do you have a dump of the params we could look at? They are shown when your app encounters an error, and typically shows you the params array which rails will pass through
Strong Params In Rails 4
Strong Params allow you to allow certain parameters for use in the controller, protecting against any malicious assignment client-side. They replaced attr_accessible in Rails 4.0
Strong Params is only for user-submitted content, as it's designed to protect the params hash. To that end, it's mostly used with the create and find functions:
class PeopleController < ActionController::Base
# Using "Person.create(params[:person])" would raise an
# ActiveModel::ForbiddenAttributes exception because it'd
# be using mass assignment without an explicit permit step.
# This is the recommended form:
def create
Person.create(person_params)
end
# This will pass with flying colors as long as there's a person key in the
# parameters, otherwise it'll raise an ActionController::MissingParameter
# exception, which will get caught by ActionController::Base and turned
# into a 400 Bad Request reply.
def update
redirect_to current_account.people.find(params[:id]).tap { |person|
person.update!(person_params)
}
end
private
# Using a private method to encapsulate the permissible parameters is
# just a good pattern since you'll be able to reuse the same permit
# list between create and update. Also, you can specialize this method
# with per-user checking of permissible attributes.
def person_params
params.require(:person).permit(:name, :age)
end
end
params.require
The params.require function works by taking this params hash:
params{:question => {:question => "1", :answer => "5"}}
That's why people asked what your params hash looks like, because the require function can only work if the :question hash is present.
Possible Solutions For You
Question.all(app_params)
Regardless of what you're trying to achieve, don't use all. The where function is better for receiving an array of data based on certain values. I believe all is depreciated anyway.
def index
#questions = Question.where("value = ?", variable)
end
What data is being passed?
I will define questions = "How are you?", "What is your name?"
This is okay, but typically in rails, you'd call data by using an ID in the database. If you're defining these questions in a form, you'd use the strong params system; but you'd need a form to submit the data to
Further Additions
The rails way is to keep all your data in a database, and use the application to manipulate that data, either by showing it, or allowing people to input more.
The "params" variables are basically there to help the rails controllers & models accept & process data from end users, and consequently allow you to keep the system growing. Instead of having to write custom code to accommodate all sorts of different data, the params give you a rigid structure to work with. Here is a good explaination of how MVC (and params) works for you: How does an MVC system work?
I think you're getting confused with how your app should work
Your "questions" should be stored in a questions table / model, and can be accessed by calling their ID's with the find function. This code would be like this:
#app/controllers/questions_controller.rb
def show
#question = Question.find(params[:id])
end
If you want to add new questions, you'll be best to add them to the questions table, like this:
#app/controllers/questions_controller.rb
def new
#question = Question.new
end
def create
#question = Question.new(question_params)
#question.save
end
private
def question_params
params.require(:question).permit(:question)
end
#app/views/questions/new.html.erb
<%= form_for #question do |f| %>
<%= f.text_field :question %>
<% end %>
This will give you a central store of your questions, which you'll then be able to access when you need them, either with a helper or with your ".all" call :)
Give it a shot with question (singular):
params.require(:question).permit(:text, :answer)
Assuming question is your model and text (which I made up) is the wording of the question.

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)

Rails3 - Permission Model Before_Save Check?

I have a permission model in my app, that ties (Users, Roles, Projects) together.
What I'm looking to learn how to do is prevent a user for removing himself for their project...
Can you give me feedback on the following?
class Permission < ActiveRecord::Base
.
.
.
#admin_lock makes sure the user who created the project, is always the admin
before_save :admin_lock
def before_save
#Get the Project Object
project = Find(self.project_id)
if project.creator_id == current_user.id
# SOME HOW ABORT OR SEND BACK Not Allowed?
else
#continue, do nothing
end
end
end
Is that look like the right approach?
Also, I'm not sure how to do the following two things above:
How to abort prevent the save, and send back an error msg?
Get the devise, current_user.id in the model, that doesn't seem possible, so how do Rails gurus do stuff like the above?
Thanks for reading through
How to abort prevent the save, and send back an error msg?
return false during the callback chain tells activemodel to stop (similar to how adding errors to the model during a validation tells it to stop at that point)
self.errors.add_to_base "msg" will add an error to the model, which can then be rendered on the view.
Get the devise, current_user.id in the model, that doesn't seem possible, so how do Rails gurus do stuff like the above?
Models shouldn't really know about things like the current request, if at all possible, you should be locking things down at the controller/action level.
EDIT:
So, the role of controllers is to deal with everything involved in getting the correct information together based on the request, and passing it to the view (which becomes the response). People often say "make your models fat and your controllers skinny", but that could be said of any system that embraces object oriented design -- your logic should be in objects when possible.
That being said, the whole point of controllers is to deal with routing the right things to the right places, and authentication is definitely a concern of routing.
You could easily move the line comparing creator_id to user id in the action, and react based on that.
Now, sometimes you genuinely need that stuff in the model and there is no way around it. That becomes a problem, because you need to fight rails to get it there. One way would be to attr_accessor a current_user field on your model, and pass that in on initialize. Another would be to remove the fields from the params hash that a user is not allowed to change in the action. Neither is really that nice though.
Agreed with Matt that you should try to use the controller for the redirect. The model should have the logic to determine if the redirect is appropriate. Maybe something like
class ProjectsController < ApplicationController
def update
redirect_to(projects_url, :alert => "You can't remove yourself from this project.") and return if Role.unauthorized_action?(:update, params[:project])
#project = Project.find(params[:id])
if #project.update_attributes(params[:project])
...
end
class Role
def self.unauthorized_action?(action, params)
# your logic here
end
You should check out CanCan for some ideas.
In permission model take one field project_creater as boolean
In project modelbefore_create :set_project_ownership
def set_project_ownership
self.permissions.build(user_id: User.current.id, project_creater: true)
end
In project controllerbefore_filter :set_current_user
In Application controllerdef set_current_user
User.current = current_user
end

Resources