views:

694

answers:

3

Hey there,

I'm currently learning RoR and I've got the following problem:

My Model, "DataFile", has a bunch of fields which I'd like to set from outside the Model, e.g.

file = DataFile.new
file.owner = 123

Now, as far as I know, I'd have to place an "attr_accessor :field" in my model, for every field that I'd like to modify from outside. However, the above code runs fine without having any attr_accessors defined, setting the owner field to 123. Why is that?

I'd expected to get a "method not defined" error or something like that.

Thanks in advance,
x3ro

+8  A: 

Because Rails' ORM uses the ActiveRecord pattern, two methods are created automatically for each column in the database associated with that table: columnname, and columnname=. This happens "automatically" as a result of your model inheriting from ActiveRecord::Base. These methods are defined using ruby's metaprogramming facilities and are created dynamically at the time of class creation.

For more info as to exactly what's going on, I would take a look at the Rails source. However, the above is probably enough to give you a working understanding of what is happening.

Drew Olson
A: 

Most likely "owner" is part of your database model. The accessors for the database fields are auto-generated for you.

Zepplock
+1  A: 

Drew and Zepplock got it right, but I'll just add one more thing. The accessors that Rails (actually, ActiveRecord) creates for database fields are NOT Ruby accessors, and if you use script/console you'll see that owner isn't an instance variable of the object file.

It's likely you'd never notice this until you venture away from the standard accessors and try to manipulate @owner inside a method on file. If you're learning Ruby at the same time you're learning Rails (which is what I did), it's likely you'll bump into this at some point. This is the reason that you need to write:

class MyClass < ActiveRecord::Base
  def invalidate_owner
    self.owner = owner << " no longer owns this"
    save
  end
end

instead of

class MyClass < ActiveRecord::Base
  def invalidate_owner
    self.owner << " no longer owns this"
    save
  end
end
Mark Westling