In Ruby, getters and setters are typically defined by using the class method `attr_accessor`. Normally you see this at the top of the class and it sort of defines what properties that instances of the class will have. I feel like this method causes some confusion for Ruby beginners and it is something I had trouble with myself when I was first starting out. So let's take a look:

class Foo
  attr_accessor :bar, :baz
end
foo = Foo.new
=> #<Foo:0x007fada99c2d00>
foo.bar
=> nil
foo.bar = 'jelly'
=> "jelly"
foo.bar
=> "jelly"
foo.baz
=> nil
foo.baz = 'time'
=> "time"
foo.baz
=> "time"

The first thing to note is that attr_accessor is different than Rails' attr_accessible. attr_accessor is a RUBY method, it has nothing to do with Rails.

Anyway, attr_accessor automatically sets up getters and setters for those instance variables. That's it. So in the above example, Foo will gain these methods:

def bar
  @bar
end

def bar=(value)
  @bar = value
end

def baz
  @baz
end

def baz=(value)
  @baz = value
end

So this is somewhat similar to Objective-C's synthesize method. Instance variables are private to the class so you expose them with these automatically generated getters and setters. Also note that since it's Ruby, you are not restricted to the true definition of "private" and you can still retrieve instance variables with instance_variable_get("@bar") and instance_variable_set("@bar", value) if you have to do some hacks. It has some interesting documentation.

 

Gripe about getters

Reminder that Ruby getters DO NOT CONTAIN "get_". There is not a single "get_" in the entire Rails repository. It is not Ruby-like so don't try to bring that Java junk in here.

If you only need to generate the getters or setters there are also two other methods. attr_reader will define only the getter methods. attr_writer will defined only the setter methods. So all attr_accessor really does is combined those two methods into one call.

 

Rails and ActiveRecord

ActiveRecord defines getters and setters for you as methods. When you call current_user.name you are calling the name method on current_user. There are not properties in Ruby like you might see on other languages. There are only getter methods that provide access to the instance variables inside of them.

So how is name defined? Luckily in Ruby you can do whatever you want, so ActiveRecord will read your database schema and generate methods on the fly when your Rails application starts. You can do this in a number of ways if you ever need to on your own, for example:

# Re-opening the User class and sticking the method into it
class User
  def name; "Whatever"; end
end

# Using class_eval to add arbitrary blocks of code to the class
User.class_eval do
  def name; "Whatever"; end
end

# Using define_method
class User
  define_method(:name) do
    "Whatever"
  end
end

ActiveRecord uses module_eval (same as class_eval) to add the getters to your model. This is done in rails/activerecord/lib/active_record/attribute_methods/read.rb (in ActiveRecord 4.1). Read is one of many modules included into your model.

Overriding ActiveRecord getters is sometimes very useful. If you do need to override something in your model then you will definitely have to call super because ActiveRecord does so much shit behind the scenes that it's useful to gain all of that for free. One nice use is when you want to use a Null Object when an attribute is nil:

def address
  super || NullAddress.new
end

Maybe you need to override a setter so you can parse a string date into a DateTime so ActiveRecord can read it and store it in a datetime column:

def started_at=(date)
  super DateTime.parse(date) # or the Chronic gem
end


SEE OUR JOB OPENINGS

Topics: Ruby on Rails, Coding & Development

Logan Serman

Written by Logan Serman

Enjoy the article? Share it!