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>
Related
I was following rails tutorial on how to use CRUD but this tutorial was using Rails 3. But because Rails 4 dropped the attr_accessible method I can't get my database to work. I am trying to create a simple blog post with a database that has a :title and content field, how would I implement this in the
Class Post < ActiveRecord::Base file
Side question: Do you recommend any good tutorials where they create an app using rails (like a blog etc) I can follow.
Thanks you
In Rails 4 you typically permit parameters at the controller level rather than defining access control at the model level.
def create
#user = user.create user_params
end
private
def user_params
params.require(:user).permit(
:name,
:age,
:shoe_size
)
end
I recommend reading Michael Hartl's Rails Tutorial. It's free to read online, or worth every penny for the printed version.
I am very new to rails, but not so much to web development. I am currently working through teamtreehouse's Build a Simple Rails application and they are using Rails 3, whereas I am using rails 4.
In the status.rb which allows the users to post a status I have the following class:
class Status < ActiveRecord::Base
attr_accessible :content, :user_id
belongs_to :user
end
I appreciate that attr_accessible has been removed from rails 4 and now using params, but any reading I do, it requires the class name to change. Does anybody have any ideas on how I can make this work?
Thanks
You remove this line from the model.
attr_accessible :content, :user_id
Then in the controller you add a method to white list the parameters that can be mass-assigned.
def status_params
params.require(:status).permit(:content, :user_id)
end
And you use that to create a new Status
def create
Status.create(status_params)
end
More in the docs http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
As you said in rails 4 attr_accessible is removed and we use strong params. To make above code work in rails 4 you'll need to make a private method status_params in your status_controller and then while creating a status or updating a status you can pass that method in params like this:
class PeopleController < ActionController::Base
def create
#status = Status.new(status_params)
#status.save
end
private
def status_params
params.require(:status).permit(:content, :user_id)
end
end
We are not changing any class here, rails 4 has simply moved the attribute accessible logic to controllers from the model. For more details read about strong parameter
Another option is to add gem 'protected_attributes' to your projects gemfile and bundle install. 'protected_attributes' gem gives you the ability to use attr_accessible and attr_protected (like in rails 3 apps) in a rails 4 app.
However, I would recommend to focus on learning how to properly use strong_params as it is important and pretty straight forward. Refer to the Ruby-on-Rails guides for detailed explanations of strong_params and controllers in general.
Also, I'd recommend that you find and use newer tutorials that are on Rails 4, there are no shortage. There are many differences between Rails 3 and 4, some of which aren't apparent on the surface and especially not to a beginner. In terms of learning, the way to go is to learn how to build a rails app with one version of the framework and to do with resources/tutorials etc that are meant for that version of Rails. As a beginner, there is no good reason for unnecessarily adding the complexity of needing to account for the intricacies and differences of Rails 3 and 4.
My class has a column secret which I generate using a specific process. Because of this, I don't want to let the user update this field via an edit form.
However, if the user adds manually the secret tag to the form and submit it, my object's secret gets updated too.
def update
object.attributes = params[:my_class]
end
I guess I create a before filter like this one
before_filter :clear_secret, :only => :update
def clear_secret
params.delete(:secret)
end
I would like to know if there is a better way to do this. Could I do this from the model? Is there a already existing Rails method for this?
If you're using Rails 3, you can protect this via attr_protected
class YourModel < ActiveRecord::Base
attr_protected :secret
end
A user attempting to inject a secret field into the form will instead cause Rails to raise a ActiveModel::MassAssignmentSecurity::Error.
However, this mechanism is deprecated in Rails 4 in favor of the strong_parameters mechanism referenced by #gylaz.
It's conventional to use strong_parameters gem to do this.
Using said gem you can permit only the attributes that can be updated, like this:
params.permit(:some_attr, :another_attr)
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)
I'm a bit of a newbie at Rails and feel I'm missing a trick here. I'm trying to add a phone_number field to my Devise-generated User model, but I'm having an issue with saving it. I've done the rails generate devise:views, updated the edit.html.erb file to add in the :phone_number field, and created a migration to add the phone_number field to the model. It's not saving to the model because (as I understand it) I can't update the controller to include the new fields.
Do I need to create an app/controllers/users/registration_controller.rb defined with class Users::RegistrationsController < Devise::RegistrationsController and then monkey patch the update method? Or is there a more straightforward/elegant/easier way?
I realize there are a couple other questions related to this on the site, but one offers no useful answers, and the other simply details what I mention here. Is there anything more to it?
Thanks.
After you add the field to your database through a migration you will also need to add it to your list of accessible attributes in your User model. Your attr_accessible list should look something like the following depending on what devise modules you are using.
attr_accessible :email, :password, :password_confirmation, :phone_number