Misunderstanding of instance variables

I'm learning Rails, and trying to setup image upload in a form. As part
of that, my image model looks something like this:

   class Image < ActiveRecord::Base
      validates_presence_of :content_type
      validates_format_of :content_type, :with => /^image/, :message =>
"must be an image"

      def image_file=(arg)
         self.content_type = arg.content_type.chomp
      end
   end

Okay, so the above basically works. But I wondered why the author I
borrowed this from used "self." instead of @ -- I thought both would
essentially reference an instance variable.

So I replaced the one line to look like this:

         @content_type = arg.content_type.chomp

and it fails, triggering my validation checks.

What gives?

I think I understand... self.content_type is an accessor, I'm
guessing, defined by ActiveRecord based on my table. So
self.content_type is a method, and @content_type is invalid. (Or at
least doesn't do what I expect.)

Does that seem right? Or am I missing something else?
Thanks...

Matthew D Moss wrote:

Okay, so the above basically works. But I wondered why the author I
borrowed this from used "self." instead of @ -- I thought both would
essentially reference an instance variable.

So I replaced the one line to look like this:
        @content_type = arg.content_type.chomp
and it fails, triggering my validation checks.

self.content_type = blahblahblah is an invocation of an instance method named "content_type=". In typical implementations of this method*, invocation causes an instance variable @content_type to be set. In the case of ActiveRecord, I guess that's not the case.

Devin
*see attr_writer

Devin Mullins wrote:

Matthew D Moss wrote:

Okay, so the above basically works. But I wondered why the author I
borrowed this from used "self." instead of @ -- I thought both would
essentially reference an instance variable.

So I replaced the one line to look like this:
        @content_type = arg.content_type.chomp
and it fails, triggering my validation checks.

self.content_type = blahblahblah is an invocation of an instance method named "content_type=". In typical implementations of this method*, invocation causes an instance variable @content_type to be set. In the case of ActiveRecord, I guess that's not the case.

Chances are, it does some extra housekeeping in addition to merely
setting the instance variable.

Bear in mind that "x.foo=" is doing a method call. If you defined that
method using attr_writer (or attr_accessor), then it will simply set
the @foo instance variable.

But if you define it manually, it may do anything and everything before
(or after) setting the variable. Or, if you wished to mislead people
or work according to some other model, foo= need not correspond to @foo
at all:

   def foo=(value)
     # Evil and nonsensical
     # Ignore the value
     puts "Haha! Fooled you!"
   end

But in this real-life case, Rails has to do a lot of "bookkeeping" and
I'll bet that's what this is about.

Hal