To use self. or not.. in Rails
def self.method_name
end
defines a class method.
def method_name
end
defines an instance method.
This is a pretty good post on it.
When to use self in Model?
When you're doing an action on the instance that's calling the method, you use self.
With this code
class SocialData < ActiveRecord::Base
def set_active_flag(val)
active_flag = val
save!
end
end
You are defining a brand new scoped local variable called active_flag, setting it to the passed in value, it's not associated with anything, so it's promptly thrown away when the method ends like it never existed.
self.active_flag = val
However tells the instance to modify its own attribute called active_flag, instead of a brand new variable. That's why it works.
How and why should I avoid using self in a Ruby method declaration
There's nothing wrong with using self, but it bypasses the requirement to create a variable instance of your object, so some die-hard OO programmers would suggest avoiding self for that reason. If you avoid "self" then you are forced to initialize your class and assign it to a variable name which forces you think of it as a true object, and not just a collection of functions.
Here's an example class to demonstrate how you would call methods with and without "self"
class StaticVersusObjectMethod
def self.class_method
puts 'Hello, static class method world!'
end
def object_method
puts 'Hello, object-oriented world!'
end
end
# No need to create an object instance variable if the method was defined with 'self'
StaticVersusObjectMethod.class_method
# You must create an object instance variable to call methods without 'self'
object = StaticVersusObjectMethod.new
object.object_method
output:
Hello, static class method world!
Hello, object-oriented world!
Whether you use self in the declaration should depend on the data you want your method to use. If the methods will only operate on the variables you pass in as parameters, then use 'self'. On the other hand, don't use 'self' if you want them to act as true object methods. "True" object methods can operate on the state of the class variables (fields) in the objects which you create and assign to a one or more variable names.
In Ruby, when should you use self. in your classes?
Use self when calling a class's mutator. For example, this won't work:
class Foo
attr_writer :bar
def do_something
bar = 2
end
end
The problem is that 'bar = 2' creates a local variable named 'bar', rather than calling the method 'bar=' which was created by attr_writer. However, a little self
will fix it:
class Foo
attr_writer :bar
def do_something
self.bar = 2
end
end
self.bar = 2
calls the method bar=
, as desired.
You may also use self to call a reader with the same name as a local variable:
class Foo
attr_reader :bar
def do_something
bar = 123
puts self.bar
end
end
But it's usually better to avoid giving a local variable the same name as an accessor.
When to use self in module's methods
Use self
in each method definition if you want the methods to be defined only in the singleton class of the module (where the methods defined using self
live). Omit self and extend self
if you want the methods of the module to be defined as instance methods and singleton methods at the same time.
For instance, you can call the method using RG::Stats.sum(array)
and still have it listed by the instance_methods
method if you do this:
module RG::Stats
extend self
def sum(a, args = {})
a.inject(0){ |accum, i| accum + i }
end
end
This way, the sum
method is defined as an instance method and it is included in the singleton class of the module after using extend self
.
You can check the instance methods of RG::Stats
module to verify this:
RG::Stats.instance_methods
=> [:sum]
With this technique you don't have to worry about defining the method without the self
keyword because modules can't have instances so it cannot be called like an instance method of RG::Stats
module. It can only be called as a singleton method RG::Stats.sum(array)
thanks to the extend self
statement.
When to use 'self' in Ruby
Whenever you want to invoke a setter method on self, you have to write self.foo = bar. If you just write foo = bar, the ruby parser recognizes that as a variable assignment and thinks of foo as a local variable from now on. For the parser to realize, that you want to invoke a setter method, and not assign a local variable, you have to write obj.foo = bar, so if the object is self, self.foo = bar
Rails -- self vs. @
The accessors for encrypted_password
have been automatically added by Rails for you because a field by that name exists in the users
table.
Any field you add to a table will be automatically made available via self.field_name
.
Here is where Michael Hartl's tutorial creates the encrypted_password
field in the users
table.
Also look at the user_spec.rb
(Listing 7.3) in the linked page, where the author is testing for the presence of the encrypted_password
field.
UPDATED:
As @mu points out, the @
is used for Ruby instance variables (aka "iv"). But encrypted_password
is an "attribute" defined by Rails, and is not an instance variable.
If you run User.find(1).instance_variables
, you will see that there is an iv called @attributes
, which is of type Hash
.
Inside that iv is where the encrypted_password
is stored. Rails has defined accessor methods for encrypted_password
, which gets/sets the data for that
attribute in the @attributes
Hash
.
Note that you could also get/set the data via @attributes["encrypted_password"]
called from within the User
class (but the accessor methods are convenient way to do just that).
Rails: when to use self
self refers to the current object.
Within a class, self is used to define a class-level method.
class Foo
def self.for(facebook_id)
User.create_by_facebook_id(facebook_id)
end
end
defines a class method for in class Foo. It is invoked:
Foo.for(facebook_id)
You can google for class methods to learn more.
It could be that a part of Rails or a plugin/gem is expecting that some classes will have a class method "for" More context would be helpful in this regard.
What the method is doing
As is common for class methods, it is creating an instance of a class. For example, the ActiveRecord class has a class method "create" which attempts to create an instance of the model class that has been stored in the database. Thus User.create will return an instance of the User class that has been stored in the database.
In your example code, it is calling a class method "create_by_facebook_id" that is provided by the User class in the application.
Looks like the "for" method is being used for information hiding since all it's doing is making another method call (to User.create_by_facebook)
Added:
By the way, the default return value from Ruby methods is the value of the last statement. So your example method will return the user instance newly created from the supplied facebook_id.
Related Topics
Best Practices For Reusing Code Between Controllers in Ruby on Rails
Find Unused Code in a Rails App
Using Www:Mechanize to Download a File to Disk Without Loading It All in Memory First
How to Do Static Content in Rails
Execute Bash Commands from a Rakefile
How to Define Action With Simple Form For
Difference Between Gemfile and Gemfile.Lock in Ruby on Rails
Limit Space and Memory Used by Imagemagick
Ruby: Parsing a String Representation of Nested Arrays into an Array
Serving Static Files With Sinatra
How to Read a User Uploaded File, Without Saving It to the Database
How to Match Accented Characters With a Regex
Haml: Append Class If Condition Is True in Haml
How to Run Rake Tasks Within a Ruby Script
Rails.Cache Error in Rails 3.1 - Typeerror: Can't Dump Hash With Default Proc
How to Install MySQL2 Gem on Windows 7
How to Understand the Difference Between Class_Eval() and Instance_Eval()