Rails attr_accesssible - ruby-on-rails

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.

Related

Rails 4 attr_accessible alternative

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.

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>

Please use new recommended protection model for params(strong_parameters) or add `protected_attributes` to your gemfile

This happened when I added an attr_accessible to my Relationship model.
class Relationship < ActiveRecord::Base
attr_accessible :followed_id
end
Without using Devise or a protected_attributes gem, what is the way around this? I know that in controllers you call a private method requiring and permitting fields. Is this something you should do in the model too? What is the convention here?
Thanks!
In Rails 4 you use Strong Parameters instead of Protected Attributes. (You don't need to include the gem in your gemfile as it's already included.)
You take the Rails 3 attr_accessible code out of your model and put corresponding code into your controller. See here for more documentation: https://github.com/rails/strong_parameters
In your case, something like:
class RelationshipController < ActionController::Base
def create
#relationship = Relationship.new(relationship_params)
if #relationship.save
# do something
else
# do something
end
end
private
def relationship_params
params.require(:relationship).permit(:followed_id)
end
end
Edit:
Here's a good article I just came across about this: http://blog.sensible.io/2013/08/17/strong-parameters-by-example.html

How could I forbid manual updates of a specific object attribute?

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)

Downcasing & Upcasing in Ruby on Rails

I have built a ruby on rails app that allows for users to track their workouts. I also allow them (like a blog) to create tags for their workouts. When users add tags to their workouts, they are assisted through auto_complete to help keep things organized.
As the site has grown in popularity I am getting a little bit of clutter/inconsistency because of capitalization. Is there a way to tell the app to only create tag.name's in uppercase or lowercase?
Try something like:
class Tag < AR::Base
before_save :downcase_name
private
def downcase_name
self.name.downcase!
end
end
Ruby has an upcase and downcase on the String class that will allow you to do either. Simply call before saving the data.
For example, if you are using the simple_auto_complete gem, you could do the following:
class BlogController < ApplicationController
autocomplete_for :post, :title do |items|
items.map {|x| x.upcase}
end
end
I can't test this right now, so forgive me if there are syntax errors.

Resources