I’m pretty mystified by this, so I would appreciate any insights…
This does involve a Rails/ActiveRecord object, but that shouldn’t matter
here, right?
I’m archiving an object when it gets deleted, so I’m chaining methods in
a Rails controller:
triplet.archive(@user.id).as_delete.save
But I checked the database and the flag never got reset from false. I
added some print statements to as_delete() to get this:
class ArchiveTriplet < ActiveRecord::Base
def as_delete
puts “MARKING: #{is_deleted}”
is_deleted = true
puts “MARKED: #{is_deleted}/#{self.is_deleted}”
return self
end
end
With an additional debug after as_delete() the log shows:
MARKING: false
MARKED: true/false
ARCHIVING: #[ArchiveTriplet…, is_deleted: false, …]
What?!
The easy solution is to change is_deleted everywhere to self.is_deleted,
but am I misunderstanding what ‘self’ is supposed to be? Is there
another keyword which means what I’ve been lead to believe ‘self’ should
mean? (ie. ‘this’ in Java)
The easy solution is to change is_deleted everywhere to self.is_deleted,
but am I misunderstanding what ‘self’ is supposed to be? Is there
another keyword which means what I’ve been lead to believe ‘self’ should
mean? (ie. ‘this’ in Java)
You just tripped into the local variable trap. The very moment you
placed “is_deleted = true” in that code you told Ruby to allocate a
local variable which is called “is_deleted” and whose value is “true”.
When you place the explicit receiver “self.” before “is_deleted” Ruby
chooses the method which accesses object state and not the local
variable.
|The easy solution is to change is_deleted everywhere to self.is_deleted
writing is_deleted = true creates a local variable and sets it to true.
Since
you don’t use that variable anywhere in your method, I guess that’s not
what
you want. I suppose what you want is to call the is_deleted= method
which is
an accessor for the @is_deleted instance variable. If it is so, then
changing
is_deleted= with self.is_deleted is not only an “easy solution” but
“the”
solution.
The reason is that writing
a_var = something
always means: create a local variable called a_var and assign it the
object
something. If you want to call a method ending in = on the current
object, you
need to explicitly tell it to ruby, using self.
|but am I misunderstanding what ‘self’ is supposed to be? Is there
|another keyword which means what I’ve been lead to believe ‘self’ should
|mean? (ie. ‘this’ in Java)
I guess my polyglotism is bleeding too much. Wrong question caused by
wrong code. Though now I have to check if since it is an ActiveRecord
object what @is_deleted = true does to the mix.
Bingo. When ruby sees a method call without an object in front of it,
the implied caller is self. Inside the method test2, self is the object
that called test2. In this case, the object ‘a’ called test2, so inside
test2 self=a. The call to meth inside test2 has no object in front of
it, so the implied caller is self. As a result, calling meth is
equivalent to self.meth which is equivalent to a.meth.
Now consider this code:
class A
def test3
x = 0
end
end
a.x = 10
a.test3
puts a.x
What’s the output? Applying the previous lessons, ‘a’ is calling test3,
so inside test3 self is ‘a’. The method call ‘x=’ inside test3 does not
have an object in front of it, so the method call x= is equivalent to
self.x=, which is equivalent to a.x=. Here’s the output:
–output:–
10
What the??!! What happened? As the smart guys pointed out in another
current thread, when the ruby parser first encounters the line:
x = 10
it tags it with the message, “create a variable called x and assign 10
to it”. As a result, ruby dutifully follows the parser’s instructions
rather than slapping ‘self’ in front of x=. In other words, an
unadorned name with = after it causes a local variable to be created
rather than calling the ‘name=’ method.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.