breaking into the unknown…

attr_reader attr_writer attr_accessor in ruby

Leave a comment

To understand this we will create a Model Employee with single field “name“, we will then experiment with its object in rails console

$ rails g model employee name:string
create    db/migrate/20130119195707_create_tests.rb
create    app/models/test.rb

The content of the model and migration file look like this

class Employee < ActiveRecord::Base

class CreateEmployees < ActiveRecord::Migration
  def change
    create_table :employees do |t|
    t.string :name

Run the migration

$ rake db:migrate

So now we have a Employee model which map to employees table with a single field name .Now let us experiment out with the employee object in the console.

Note : If you make any change in file, reload the console, before trying out your changes, otherwise it will not reflect

1.9.2-p290 :003 > reload!
=> true

1.9.2-p290 :038 > # creating instance i,e object of Employee
=> #<Employee id: nil, name: nil>

1.9.2-p290 :002 >
=> nil #output is o.k as we have not set any name yet
1.9.2-p290 :003 > = "Arun"
=> "Arun" # employee name set to Arun
1.9.2-p290 :004 >
=> "Arun" # employee name is correctly output

Now, let us try to set age of employee

1.9.2-p290 :004 > employee.age = 23
NoMethodError: undefined method `age=' for #<Employee:0x97aac48>

let us try to see age of employee

1.9.2-p290 :004 > employee.age = 23
NoMethodError: undefined method `age' for #<Employee:0x97aac48>

What, is this , why we are not able to see or set age in the same way as we are doing for employee name. You may thought, the error is because we have name filed in employees table but not the age filed.But you see it is not a database error but undefined method `age=’ error. O.k so they are looking for method age= and age, let us define them

class Employee < ActiveRecord::Base
  def age= val
    @age = val # age set to val

  def age
    @age # age is returned i,e read

#let us define some other method to try them in console

#we want secret to be only set on object but no one to read them
  def secret= val
    @secret = val

#we want employee code to be only read from object no one can set it
  def employee_code

Now, let us checkout different operation on console

1.9.2-p290 :038 > # creating instance i,e object of Employee
=> #<Employee id: nil, name: nil>
1.9.2-p290 :004 > employee.age=23
=> 23
1.9.2-p290 :005 > employee.age
=> 23
1.9.2-p290 :007 > employee.secret = "xyzw"
=> "xyzw"
1.9.2-p290 :008 > employee.secret
1.9.2-p290 :009 > employee.employee_code
=> nil
1.9.2-p290 :010 > employee.employee_code = 1234
NoMethodError: undefined method `employee_code=' for #<Employee:0x9c7e6ac>

So, we can see that any one can set and read age from the object, but for security reason they can only set secret but can’t read and in case of employee_code they can only read it but not set it.

But, still we can’t see any name method in our model then how it is working and from where it is coming, Actually, ruby do a lot of things for you from behind the scene, It has defined name and name= method internally for you along with a large no of other methods which you are not even aware of….you better know them as it will reduce your line of code. all methods available to any object can be listed by calling methods on it

1.9.2-p290 :011 > employee.methods
=> [:age=, :age, :secret=, :employee_code, :name, :name=, :name_before_type_cast, 
:name?, :name_changed?, :name_change, :name_will_change!, :name_was, :reset_name!
, on.......]

So, you can see a no of methods being created for name filed, you can try all of them in console, as for name field these methods are created for all the fields in the corresponding table of a model….great… so what about any attributes which we do not have in table but just want on a object after its creation…well you have attr_reader attr_writer attr_accessor for that.

Let us cut down our model code to three line. This will internally generate all the methods, you have defined above

class Employee < ActiveRecord::Base
  attr_accessor :age   # make age writable and redable
  attr_writer :secret #make secret only writable
  attr_reader :employee_code # make it only readable

If you again check in console, you will find your required method there

1.9.2-p290 :011 > employee.methods
=> [:age=, :age, :secret=, :employee_code, :name, :name=, :name_before_type_cast, :name?,  :name_changed?,

:name_change, :name_will_change!, :name_was, :reset_name!,…………so on…….]

Author: arunyadav4u

over 7 years experience in web development with Ruby on Rails.Involved in all stage of development lifecycle : requirement gathering, planing, coding, deployment & Knowledge transfer. I can adept to any situation, mixup very easily with people & can be a great friend.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s