When I use the attr_accessible to specify which fields from my Model I will expose, is it true for script/console as well? I mean something that I didn't specify as attr_accessible won't be accessible as well through console ?
This is only true for mass assignment. For instance, if you were to set attr_protected :protected in your model:
>> Person.new(:protected => "test")
=> #<Person protected: nil>
Conversely, you could set all attributes you want as accessible using attr_accessible.
However, the following will still work:
>> person = Person.new
=> #<Person protected: nil>
>> person.protected = "test"
=> #<Person protected: "test">
This is the same behaviour as in controllers, views, etc. attr_protected only protects against mass assignment of variables, primarily from forms, etc.
The console behaves exactly as your Rails application. If you protected some attributes for a specific model, you won't be able to mass assign these attributes either from console or from the Rails app itself.
I found why:
Specifies a white list of model attributes that can be set via mass-assignment, such as new(attributes), update_attributes(attributes), or attributes=(attributes).
This is the opposite of the attr_protected macro:
Mass-assignment will only set attributes in this list, to assign to the rest of
attributes you can use direct writer methods. This is meant to protect sensitive
attributes from being overwritten by malicious users tampering with URLs or forms.
If you‘d rather start from an all-open default and restrict attributes as needed,
have a look at `attr_protected`.
So it means that it just avoid mass-assignment but i can still set a value.
When you specify somethings to be attr_accessible only those things can be accessed in console or by website Interface.
eg: Suppose you made name and email to be attr_accessible:
attr_accessible :name, :email
and left out created_at and updated_at (which you are supposed to).
Then you can only edit/update those fields in console.
If you want to expose a field form your model, you can use
attr_accessor :meth # for getter and setters
attr_writer :meth # for setters
attr_reader :meth # for getters
or if you want add some behaviour to your attribute, you ll have to use virtual attributes
def meth=(args)
...
end
def meth
...
end
cheers.
Related
I'm working on a RubyonRails/ActiveAdmin application. My RoR version is 4.2.5 and AA version is 1.0.0. I have a model Message as follows.
class Message < ActiveRecord::Base
belongs_to :user
validates :user, :content, presence: true
def palindrome
# return true/false
end
end
As you see, I want to have a read-only attribute palindrome which only depends on the content of message. I want this attribute to be treated exactly like a normal attribute. By normal, I mean when I retrieve messages via rails console or request json format of messages, I want to see a palindrome attribute in the list. I would also like to have a filter for message by this attribute.
I'm not sure how could I achieve this.
Ruby actually lets you create virtual attributes this way, which keeps you from having to manually create getter and setter methods:
attr_reader :palindrome #getter
attr_writer :palindrome #setter
attr_accessor :palindrome #both
You can also pass multiple arguments too:
attr_accessor :palindrome, :foo, :bar
The documentation for it isn't the greatest.
In your model, you can write attribute accessors (reader/writer) for your virtual attribute palindrome attribute this way:
# attr_reader
def palindrome
self[:palindrome]
end
# attr_writer
def palindrome=(val)
self[:palindrome] = val
end
# virtual attribute
def palindrome
#return true/false
end
And, as you are using Rails 4, you have to whitelist palindrome attribute like any other model attribute in your strong param definition inside your controller in order to able to mass assign the value of palindrome. Something like this:
# your_controller.rb
private
def your_model_params
params.require(:message).permit(:palindrome)
end
Take a look at this RailsCast on Virtual Attributes. Although, it's a bit old, but would be useful for concepts.
Note:
A virtual attribute will not show up in the param list automatically. But, you should be able to access it via Rails console like this: Message.new.palindrome. Also, you can expose this virtual attribute in your JSON API, for example if you are using Active Model Serializer, you can have: attribute palindrome in your MessageSerializer and then palindrome will be exposed to the JSON API.
Since Rails 5 you can also set virtual attributes like this:
attribute :palindrome, :boolean
It automatically casts the attribute to the specified type, which can be useful when the value comes from forms. This GoRails video shows some really good examples of both using the attr_accessor and the attribute approach. The documentation also includes some examples.
When a form is submitted, how to prevent a single attribute from being updated in Rails? All other attributes should be updated.
Is it before_save, attr_reader or some other way?
If using before_save, how to access to the attributes hash?
Rails 3.0.7
Check out attr_protected.
Class YourModel << ActiveRecord::Base
attr_protected :the_one_column, as: :update
# ...
end
Now as part of a call to update_attributes, you'd specify the :update role, for example
klass = YourModel.find(some_id)
klass.update_attributes(params[:your_model], as: :update)
If :the_one_column is set in params passed to update_attributes, it will throw an error.
As #Beerlington mentioned in his comment to your Question, you should also check out attr_accessible. It's generally better to spend the 30 minutes going through all models of your application white-listing attributes using attr_accessible than it is to blacklist specific attributes with attr_protected.
Other option is simply doing this in your controller:
klass.update_attributes( params[:your_model].except(:attributes_to_avoid) )
I need to access attribute names of a model but it is not showing all of them.
I have User model and I added a attr_accessor :color in it (since I don't want to store this on my database as column).
But if I try to access attribute names using User.first.attribute_names it is showing only database columns,it is not showing 'color' attribute,so how do I access all the attributes ?is there any methods which list attr_accessor as attributes ?
User.accessible_attributes #will return array of accessible attributes
First of all if you don't know difference b/w attr_acessabe and attr_accessor look at
How to iterate ActiveRecord Attributes, including attr_accessor methods
you can add attr_accessor if you don't an attribute to save in database then add that att_accessor to attr_accessable :)
attr_accessor :color
attr_accessible :color
now
User.accessible_attributes # => ["color"], but beware that you have lost all other attribute you need to add those too if you want to enable mass assignment.
attr_accessible :color,:first_name,:blah,:blah...
Have you tried #methods i.e. User.first.methods or perhaps User.accessible_attributes is more in line with what your looking for.
What I have:
class User < ActiveRecord::Base
attr_accessor :notify
end
User.new(args)
What I'm doing:
User.new(args)
User.notify = true
What I need is something like:
User.new(args.merge(:notify => true))
What you have shown will work. Make sure to include :notify in the list of attributes for attr_accessible if you are using that.
As long as you have the attr_accessor defined, including the variable in any ActiveRecord mass assignment will work. As "Wizard of Ogz" mentioned, limiting access to the attributes affects both database attributes and instance variables alike.
In Rails, what is the difference between attr_accessor and attr_accessible? From my understanding, using attr_accessor is used to create getter and setter methods for that variable, so that we can access the variable like Object.variable or Object.variable = some_value.
I read that attr_accessible makes that specific variable accessible to the outside world.
Can someone please tell me whats the difference
attr_accessor is a Ruby method that makes a getter and a setter. attr_accessible is a Rails method that allows you to pass in values to a mass assignment: new(attrs) or update_attributes(attrs).
Here's a mass assignment:
Order.new({ :type => 'Corn', :quantity => 6 })
You can imagine that the order might also have a discount code, say :price_off. If you don't tag :price_off as attr_accessible you stop malicious code from being able to do like so:
Order.new({ :type => 'Corn', :quantity => 6, :price_off => 30 })
Even if your form doesn't have a field for :price_off, if it's in your model it's available by default. This means a crafted POST could still set it. Using attr_accessible white lists those things that can be mass assigned.
Many people on this thread and on google explain very well that attr_accessible specifies a whitelist of attributes that are allowed to be updated in bulk (all the attributes of an object model together at the same time)
This is mainly (and only) to protect your application from "Mass assignment" pirate exploit.
This is explained here on the official Rails doc : Mass Assignment
attr_accessor is a ruby code to (quickly) create setter and getter methods in a Class. That's all.
Now, what is missing as an explanation is that when you create somehow a link between a (Rails) model with a database table, you NEVER, NEVER, NEVER need attr_accessor in your model to create setters and getters in order to be able to modify your table's records.
This is because your model inherits all methods from the ActiveRecord::Base Class, which already defines basic CRUD accessors (Create, Read, Update, Delete) for you.
This is explained on the offical doc here Rails Model and here Overwriting default accessor (scroll down to the chapter "Overwrite default accessor")
Say for instance that: we have a database table called "users" that contains three columns "firstname", "lastname" and "role" :
SQL instructions :
CREATE TABLE users (
firstname string,
lastname string
role string
);
I assumed that you set the option config.active_record.whitelist_attributes = true in your config/environment/production.rb to protect your application from Mass assignment exploit. This is explained here : Mass Assignment
Your Rails model will perfectly work with the Model here below :
class User < ActiveRecord::Base
end
However you will need to update each attribute of user separately in your controller for your form's View to work :
def update
#user = User.find_by_id(params[:id])
#user.firstname = params[:user][:firstname]
#user.lastname = params[:user][:lastname]
if #user.save
# Use of I18 internationalization t method for the flash message
flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
end
respond_with(#user)
end
Now to ease your life, you don't want to make a complicated controller for your User model.
So you will use the attr_accessible special method in your Class model :
class User < ActiveRecord::Base
attr_accessible :firstname, :lastname
end
So you can use the "highway" (mass assignment) to update :
def update
#user = User.find_by_id(params[:id])
if #user.update_attributes(params[:user])
# Use of I18 internationlization t method for the flash message
flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
end
respond_with(#user)
end
You didn't add the "role" attributes to the attr_accessible list because you don't let your users set their role by themselves (like admin). You do this yourself on another special admin View.
Though your user view doesn't show a "role" field, a pirate could easily send a HTTP POST request that include "role" in the params hash. The missing "role" attribute on the attr_accessible is to protect your application from that.
You can still modify your user.role attribute on its own like below, but not with all attributes together.
#user.role = DEFAULT_ROLE
Why the hell would you use the attr_accessor?
Well, this would be in the case that your user-form shows a field that doesn't exist in your users table as a column.
For instance, say your user view shows a "please-tell-the-admin-that-I'm-in-here" field.
You don't want to store this info in your table. You just want that Rails send you an e-mail warning you that one "crazy" ;-) user has subscribed.
To be able to make use of this info you need to store it temporarily somewhere.
What more easy than recover it in a user.peekaboo attribute ?
So you add this field to your model :
class User < ActiveRecord::Base
attr_accessible :firstname, :lastname
attr_accessor :peekaboo
end
So you will be able to make an educated use of the user.peekaboo attribute somewhere in your controller to send an e-mail or do whatever you want.
ActiveRecord will not save the "peekaboo" attribute in your table when you do a user.save because she don't see any column matching this name in her model.
attr_accessor is a Ruby method that gives you setter and getter methods to an instance variable of the same name. So it is equivalent to
class MyModel
def my_variable
#my_variable
end
def my_variable=(value)
#my_variable = value
end
end
attr_accessible is a Rails method that determines what variables can be set in a mass assignment.
When you submit a form, and you have something like MyModel.new params[:my_model] then you want to have a little bit more control, so that people can't submit things that you don't want them to.
You might do attr_accessible :email so that when someone updates their account, they can change their email address. But you wouldn't do attr_accessible :email, :salary because then a person could set their salary through a form submission. In other words, they could hack their way to a raise.
That kind of information needs to be explicitly handled. Just removing it from the form isn't enough. Someone could go in with firebug and add the element into the form to submit a salary field. They could use the built in curl to submit a new salary to the controller update method, they could create a script that submits a post with that information.
So attr_accessor is about creating methods to store variables, and attr_accessible is about the security of mass assignments.
attr_accessor is ruby code and is used when you do not have a column in your database, but still want to show a field in your forms. The only way to allow this is to attr_accessor :fieldname and you can use this field in your View, or model, if you wanted, but mostly in your View.
Let's consider the following example
class Address
attr_reader :street
attr_writer :street
def initialize
#street = ""
end
end
Here we have used attr_reader (readable attribute) and attr_writer (writable attribute) for accessing purpose. But we can achieve the same functionality using attr_accessor. In short, attr_accessor provides access to both getter and setter methods.
So modified code is as below
class Address
attr_accessor :street
def initialize
#street = ""
end
end
attr_accessible allows you to list all the columns you want to allow Mass Assignment. The opposite of this is attr_protected which means this field I do NOT want anyone to be allowed to Mass Assign to. More than likely it is going to be a field in your database that you don't want anyone monkeying around with. Like a status field, or the like.
In two words:
attr_accessor is getter, setter method.
whereas attr_accessible is to say that particular attribute is accessible or not. that's it.
I wish to add we should use Strong parameter instead of attr_accessible to protect from mass asignment.
Cheers!
A quick & concise difference overview :
attr_accessor is an easy way to create read and write accessors in
your class. It is used when you do not have a column in your database,
but still want to show a field in your forms. This field is a
“virtual attribute” in a Rails model.
virtual attribute – an attribute not corresponding to a column in the database.
attr_accessible is used to identify attributes that are accessible
by your controller methods makes a property available for
mass-assignment.. It will only allow access to the attributes that you
specify, denying the rest.