Why do I have to refer to my attr_accessible as self.varname?

I posted a previous message about overriding initialize… because I was
having issues setting some of the parameters. I have a Page model that
has:

attr_accessible :url, :title, :doc, :domain

and it’s called via:

Page.new(:url => ‘http://www.yahoo.com’)

Since I’m only passing in the url to new, I needed to set the other
parameters. I was trying to do this via an after_initialize callback
which
wasn’t working so tried overriding initialize… still not working.

What I found out was that in my after_initialize, I was referring to
title
as @title which is why it was not working. I switched it to self.title
and
it works fine.

My question is - why?

On Dec 21, 2012, at 12:37 PM, Dan B. wrote:

What I found out was that in my after_initialize, I was referring to title as
@title which is why it was not working. I switched it to self.title and it works
fine.

My question is - why?

@title is an instance variable. Until you set it, it doesn’t exist.
Having a method on the model called title (or an accessor, or some other
Rails magick) does not instantiate that method’s return until and unless
you ask for it by calling the method. Calling self.method_name just
makes it clear which same-named method you really mean. Self is implied
much of the time, but when you have all the many method_missing options
available, it might not be the first one such that gets called.

Walter

On Dec 21, 2012, at 1:12 PM, Dan B. wrote:

def parse_page_params
@title = “test”
end

Have a look at the documentation for after_initialize – it runs once,
after Rails itself is fully initialized. Is that the point at which you
mean to instantiate the instance variable @title? Which instance of its
class would it attach to? Can you please describe what you intend to do
with @title – where it’s going to be used?

Walter

I would use a before_save or what it is called if I were you.
Am 21.12.2012 19:40 schrieb “Walter Lee D.” [email protected]:

So is the way I’m doing it right? Or just a way I happened to hack it
to
work?

The way my code was looking was basically:

Page.new(:url => ‘http://www.yahoo.com’)

class Page < ActiveRecord::Base
attr_accessible :url, :title

after_initialize :parse_page_params

def parse_page_params
@title = “test”
end

and this wasn’t working… I understand what you said above about the
instance variables, methods, initializing, etc… but still a little
unclear
about why that code doesn’t work as I’m setting it. Is it because Rails
uses the method name of title which hasn’t been initailized in my
assignment above?

On Dec 21, 6:12pm, Dan B. [email protected] wrote:

instance variables, methods, initializing, etc… but still a little unclear
about why that code doesn’t work as I’m setting it. Is it because Rails
uses the method name of title which hasn’t been initailized in my
assignment above?

Because rails doesn’t use individual instance variables to store your
attributes (whether they’ve been marked as attr_accessible makes no
difference)

title = “foo”

Doesn’t work because ruby assumes that you want to assign to the local
variable called title. Doing self.title = makes it clear that you want
to call the title= accessor

Fred

I do something similar in a project of mine. I have an API key and
retrieve
user information after he logs in. This works very fine in an
after-find,
why should that not work in a before_save?

Can’t provide the source right now. I have no access until Jan 8th.
Am 21.12.2012 22:39 schrieb “Dan B.” [email protected]:

On Friday, 21 December 2012 13:12:35 UTC-5, Dan B. wrote:

assignment above?

It sounds like you’ve got attr_accessible and attr_accessor somewhat
entangled in your mental model. They aren’t really the same thing at
all:

  • attr_accessible: specifies which attributes are mass-assignable
    (through
    things like Page.new(:some_attribute => ‘foo’)) and which have to be
    assigned individually.

  • attr_accessor: creates two accessor methods that wrap an instance
    variable. So this:

attr_accessor :something

is shorthand for this:

def something
@something
end

def something=(v)
@something = v
end

Occasionally you’ll even see both used for a particular name, as the
developer wants to create an attribute that isn’t persisted to the
database
but can be mass-assigned (from a form submission, for instance).

–Matt J.

What I’m trying to do is parse out the title and then save it to the DB
for
quick display on the webpage.

I could do a before_save, hadn’t thought of that, but would I have the
same
issues? I’m basically doing a Page.new(…), a few lines of validation,
and
then Page.save() so before_save would be ok I guess. Is there typically
a
standard way of doing things?

Frederick C. wrote in post #1089897:

Because rails doesn’t use individual instance variables to store your
attributes (whether they’ve been marked as attr_accessible makes no
difference)

title = “foo”

Doesn’t work because ruby assumes that you want to assign to the local
variable called title. Doing self.title = makes it clear that you want
to call the title= accessor

While true, that has nothing to do with the op’s problem–the op is
assigning to an @ variable, and an @ variable, like @title, can never be
a local variable. There is only one way for ruby to interpret an
assignment like:

@title = some_value

Is there typically a standard way of doing things?

Yes. Always use the accessor method to set or get the value of an
instance variable. Here is an example of how things can go wrong:

class Dog
def title=(val)
@title = val.capitalize
end

def title
@title
end

def do_stuff
@title = “mr.”
@title + " Dog"
end
end

puts Dog.new.do_stuff

–output:–
mr. Dog

And here is how to correct the problem:

class Dog
def title=(val)
@title = val.capitalize
end

def do_stuff
self.title = “mr.”
title + " Dog"
end
end

puts Dog.new.do_stuff

What you did is bypass an accessor method, which you did not define and
therefore are blissfully unaware of what it does, and your results
showed that the accessor method did something critical.

The solution is similar to why you should call super inside your class’s
initialize() method when you inherit from a complicated class hierarchy:
you need to let classes higher up in the chain proceed with the
machinations they require to set up everything correctly.

7stud – wrote in post #1089991:

And here is how to correct the problem:

class Dog
def title=(val)
@title = val.capitalize
end

def do_stuff
self.title = “mr.”
title + " Dog"
end
end

puts Dog.new.do_stuff

I left out the getter:

class Dog
def title=(val)
@title = val.capitalize
end

#MISSING getter **********
def title
@title
end

def do_stuff
self.title = “mr.”
title + " Dog"
end
end

puts Dog.new.do_stuff

–output:–
Mr. Dog