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, :bazend
foo = Foo.new=> #<Foo:0x007fada99c2d00>foo.bar=> nilfoo.bar = 'jelly'=> "jelly"foo.bar=> "jelly"foo.baz=> nilfoo.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 @barenddef bar=(value) @bar = valueenddef baz @bazenddef baz=(value) @baz = valueend
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 itclass User def name; "Whatever"; endend# Using class_eval to add arbitrary blocks of code to the classUser.class_eval do def name; "Whatever"; endend# Using define_methodclass User define_method(:name) do "Whatever" endend
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.newend
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 gemend