When I started learning Ruby, I started with Michael Hartl's excellent Rails Tutorial. I just revisited the tutorial and noticed that portions of the example application code were modified. In the authentication chapter two methods were changed:
# SessionsHelper
def sign_in(user)
...
self.current_user = user
end
def sign_out
self.current_user = nil
...
end
Previously, the keyword self was omitted. But the app worked. So, if it ain't broke, why fix it? What value has self added and why is it used?
I understand that self defines class methods as opposed to instance methods. And in models, using self allows us to reference an object's property directly. But I can't tie the dots and see how it's being used in a helper. I've seen it in controllers before and I can't understand why we would want to use it there.
[Edit]
It is likely that the original section of the tutorial was just plain wrong. Omitting the "self" receiver causes the methods to assign a value to the method local variable "current_user" with no other effect.
My original answer below is incorrect and should be ignored (because writer methods foo=(x) cannot be called without a receiver, as can other methods).
[Incorrect Original Answer Below]
The reason for using the "self" receiver is likely for clarity.
If "self" is omitted then, to the untrained eye, it looks like you are simply assigning the "user" variable to a new variable named "current_user" with no other effect. Experienced Rubyists know that if there is a method named "current_user" on the object instance then it will be called instead of just creating and assigning a new variable but this detail can easily be overlooked, especially if the method is inherited or otherwise not declared in the current class definition section.
By using the "self" keyword explicitly you are clearly stating that you are calling a method on this object instance.
class User
attr_accessor :current_user
def sign_in_1
# Assigning local variable here
current_user = "Foo"
end
def sign_in_2
# Calling accessor method
self.current_user = "Bar"
end
end
u = User.new
u.sign_in_1
p u.current_user #=> nil
u.sign_in_2
p u.current_user #=> "Bar"
Related
Just want to enquire what the right practice is.
My preference is to use procs, simply because I think that defining methods inside of methhods is a bit untidy and should be done only when necessary. To get around it, I simply use procs.
What is the right / better way to do it and why? (apart from the proc's ability to access the main method's variables defined before itself)
def meth( params_prime )
calculations = do_something_with_whatever
def sub_meth( params_sub )
do_something_with_params_sub
end
sub_meth_params(calculations) # is this better?
proc1 = proc{ |params_sub| do_something_with_params_sub }
proc1.call(calculations) # or is this?
end
It is not clear what your specific use-case is, but I would definitely go for procs or lambdas. There is less overhead when defining a proc or lambda dynamically, they are passable, so if needed you could return them and they could be used outside the function.
Using "def" exposes the method as an instance method outside of the current method scope (so in the containing class, which could be Object in your case). This may or may not be with you want. If you want to use an anonymous function only available in the local scope, use a lambda.
Also Proc vs Lambda: I generally prefer to use lambdas since they behave a little more "predictable", meaning: as you would expect (check passed variables, and return just returns from the lambda, proc returns from the called scope). But from your example it is hard to deduce what would apply. I think the key-difference is: lambas are ment to be passed around, and thus behave a little more sanely. If this is not your use-case, use Proc :) (a write-up of the difference).
If you want to use sub_func to encapsulate it from call from other methods you can use a class to group function and sub_func together and make sub_func private. Otherwise if you want to pass this function as a parameter further you can declare it as lamda.
def func params_prime
sub_func = ->(params_sub){do_something_with_params}
sub_func.call(params_prime)
end
Defining methods inside methods is a feature of Ruby that may have its use. But something is telling me that you are asking a very advanced question while you are still a beginner level Rubyist. Do you know what default definee is? If not, check this article by Yugui.
Procs are very important in Ruby, but newbies tend to use them instead of defining methods in appropriate objects, which is the exact smell I'm getting from your question. The normal way of doing things in OO languages of Ruby family is to define methods on objects:
class Foo
def bar *params
# do something with params
end
end
Since you do not understand the meaning of defining methods inside methods, refrain from doing it for the next 6 months. Once you understand objects, you can start experimenting with this very advanced feature again.
APPENDIX:
Since you demonstrated intrest, let me show you that using def in def at the top level is a frownable-upon thing to do. Normally, when you define a method on some class without further adornment, it becomes a public instance method of that class:
class X
def foo; "foo" end
end
X.instance_methods.include? :foo
#=> true
When you use def in a def, the definee for the inner def is going to be X:
class X
def bar
def baz
"baz"
end
"bar"
end
end
When you execute the above code, instance method #bar becomes defined on X:
X.instance_methods.include? :bar
#=> true
But #baz not yet:
X.instance_methods.include? :baz
#=> false
Only after you call #bar at least once does the method become defined on X:
X.new.bar
#=> "bar"
X.instance_methods.include? :baz
#=> true
And now I would like to ask you to appreciate how terrible thing just happened: An instance just modified its mother class. That's a violation. A violation of such a basic principle of OO design, that I'm not even sure it has a name. This technique is great for obfuscated coding competitions, but in production, it's taboo. Ruby gives you the freedom to break that taboo, gives you the rope to hang yourself on, but you don't do it under any kind of normal circumstances.
So what can be worse than a def inside a def in a class definition? The answer is, a def inside a def at the top level. Let me show you why. Normally, when you define methods with def at the top level, the default definee is Object, but the top level defnitions become private instance methods of object. This is to prevent the unintended consequence of top level defs, because almost all Ruby objects inherit from Object. For example, if you define:
class Object
def foo; "foo" end
end
Now all your objects will respond to foo:
foo #=> "foo"
1.foo #=> "foo"
[].foo #=> "foo
When we define methods at the top level, we usually just intend to use the method at the top level, and don't want every single object to inherit it. For that reason, top level defs become private:
hello #=> NameError: undefined local variable or method `hello' for main:Object
1.hello #=> NoMethodError: undifined method 'hello' for 1:Fixnum
Now we use def at the top level:
def hello; "hello" end
We can see that method #hello is has not become an instance methods of Object:
Object.instance_methods.include? :hello
#=> false
Mysteriously, it became its private method:
Object.private_instance_methods.include? :hello
#=> true
This way, we avoid the unintended consequence of defining #hello method for every single object. But the inheritance is there. The error message has changed:
1.hello #=> NoMethodError: private method 'hello' called for 1:Fixnum
And we can forcibly call the method via #send:
1.send :hello
#=> "hello"
Mysteriously, at the top level, we are allowed to call this private method without #send:
hello
#=> "hello"
And now, what happens when you do def in def at the top level:
def bar
def baz; "baz" end
"bar"
end
You define a private instance method Object#bar in an expected way. But when you call it, alas, the top level magic no longer works and a public method Object#baz gets defined:
bar #=> "bar"
This way, not just the top level, but every single Ruby object got polluted with your #baz method:
1.baz #=> "baz"
Class.baz #=> "baz"
This is why I told you to refrain from using this idiom until you progress from the level of unconscious incompetence to the level of conscious incompetence. I recommend you to read more about top level methods in Ruby.
In the following example everything is logical for me:
class Something
def initialize
#x=101
end
def getX
return #x
end
end
obj = Something.new
puts obj.getX
=>101
Something.new will create new instance of class Something with instance variable #x which will be visible to all methods of class Something.
But what will happen in second example without initialize(constructor) method.
class Something
def bla_bla_method
#x=101
end
def getX
return #x
end
end
obj = Something.new
puts obj.getX
=>nil
obj.bla_bla_method
puts obj.getX
=>101
So now bla_bla_method when called will create(like constructor) new instance_variable #x and will add that instance variable in "instance variable table" which is available to all methods again?
So now if i add new method "new_method" in class Something(in second example):
def new_method
#x=201
end
...
obj.bla_bla_method
puts obj.getX
=>101
obj.new_method
puts obj.getX
=>201
So if im getting this right, every method of class can create new instance variable which is available to all methods of class? And then every method can overwrite that instance variable over and over again(cyclical)?
I'm new to ruby so maybe here i'm doing big mistake or don't understand some basic concept , so dont yell :D
Instance variables for an object can be named and manipulated while the object exists. See the example below, when we are using the irb prompt object:
$ irb
> instance_variables # => [:#prompt]
> #foo # => nil
> instance_variables # => [:#prompt]
> #foo = 1 # => 1
> instance_variables # => [:#prompt, :#foo]
> #foo # => 1
Now, here's a description of Class#new from the docs:
Calls allocate to create a new object of class’s class, then invokes that object’s initialize method, passing it args. This is the method that ends up getting called whenever an object is constructed using .new.
One way to think of this is that initialize is functionally a regular method just like your other instance methods, only it gets called by Class#new to provide us with an easy way of setting default values (among others).
Technically, yes. But consider the notion of Object Oriented programming - Creating real world abstractions in form of classes and objects.
For instance, if you are talking about a student in a school; you know that is an abstractable entity. So you go ahead and encapsulate the common characteristic of student in a class Student.
initialize is a constructor. When you create a new student in your system, you would naturally want to supply few necessary details about him like his name, age and class.
So in initialize method you set those instance variables.
Few students also study in school; so naturally they will acquire some grade and stuff; to instantiate those details about the student, you would want to do that with something like this:
#Student(name, age, class)
kiddorails = Student.new("Kiddorails", 7, 2)
#to grade:
kiddorails.set_grades
#do stuff
So you can mutate and set the instance variables in an object, almost anywhere you want in a class; but the point is - Do it, where it makes sense.
PS: You should always set default values to the instance variables which are not set via initialize in initialize, if needed.
I Just started learning ruby and I don't see the difference between an #instace_variable and an attribute declared using attr_accessor.
What is the difference between the following two classes:
class MyClass
#variable1
end
and
class MyClass
attr_accessor :variable1
end
I searched lot of tutorials online and everybody uses different notation, Does it have to do anything with the ruby version? I also searched few old threads in StackOverflow
What is attr_accessor in Ruby?
What's the Difference Between These Two Ruby Class Initialization Definitions?
But still I am not able to figure out what is the best way to use.
An instance variable is not visible outside the object it is in; but when you create an attr_accessor, it creates an instance variable and also makes it visible (and editable) outside the object.
Example with instance variable (not attr_accessor)
class MyClass
def initialize
#greeting = "hello"
end
end
m = MyClass.new
m.greeting #results in the following error:
#NoMethodError: undefined method `greeting' for #<MyClass:0x007f9e5109c058 #greeting="hello">
Example using attr_accessor:
class MyClass
attr_accessor :greeting
def initialize
#greeting = "hello"
end
end
m2 = MyClass.new
m2.greeting = "bonjour" # <-- set the #greeting variable from outside the object
m2.greeting #=> "bonjour" <-- didn't blow up as attr_accessor makes the variable accessible from outside the object
Hope that makes it clear.
Instance variables are not directly visible outside of the class.
class MyClass
def initialize
#message = "Hello"
end
end
msg = MyClass.new
#message
#==> nil # This #message belongs to the global object, not msg
msg.message
#==> NoMethodError: undefined method `message'
msg.#message
#==> SyntaxError: syntax error, unexpected tIVAR
Now, you can always do this:
msg.instance_eval { #message }
or ask for the variable directly like this:
msg.instance_variable_get :#message
But that's awkward and sort of cheating. Poking around someone else's class may be educational, but your client code shouldn't be required to do it to get reliable results. So if you want clients to be able to see those values, don't make them use the above techniques; instead, define a method to expose the value explicitly:
class MyClass
def message
return #message
end
end
msg.message
# ==> "Hello"
Because you so often want to do that, Ruby provides a shortcut to make it easier. The code below has exactly the same result as the code above:
class MyClass
attr_reader :message
end
That's not a new type of variable; it's just a shorthand way to define the method. You can look at msg.methods and see that it now has a message method.
Now, what if you want to allow outsiders to not only see the value of an instance variable, but change it, too? For that, you have to define a different method for assignment, with a = in the name:
class MyClass
def message=(new_value)
#message = new_value
end
end
msg.message = "Good-bye"
msg.message
# ==> "Good-bye"
Note that the assignment operators are semi-magical here; even though there's a space between msg.message and =, Ruby still knows to call the message= method. Combination operators like += and so on will trigger calls to the method as well.
Again, this is a common design, so Ruby provides a shortcut for it, too:
class MyClass
attr_writer :message
end
Now, if you use attr_writer by itself, you get an attribute that can be modified, but not seen. There are some odd use cases where that's what you want, but most of the time, if you are going to let outsiders modify the variable, you want them to be able to read it, too. Rather than having to declare both an attr_reader and an attr_writer, you can declare both at once like so:
class MyClass
attr_accessor :message
end
Again, this is just a shortcut for defining methods that let you get at the instance variable from outside of the class.
attr_accesor gives you methods to read and write the instance variables. Instance variables are deasigned to be hidden from outside world so to communicate with them we should have attr_ibute accesor methods.
In OOPS we have a concept called encapsulation which means, the internal representation of an object is generally hidden from view outside of the object's definition. Only the Object 'itself' can mess around with its own internal state. The outside world cannot.
Every object is usually defined by its state and behavior, in ruby the instance variables is called internal state or state of the object and according to OOPS the state should not be accessed by any other object and doing so we adhere to Encapsulation.
ex: class Foo
def initialize(bar)
#bar = bar
end
end
Above, we have defined a class Foo and in the initialize method we have initialized a instance variable (attribute) or (property). when we create a new ruby object using the new method, which in turn calls the initialize method internally, when the method is run, #bar instance variable is declared and initialized and it will be saved as state of the object.
Every instance variable has its own internal state and unique to the object itself, every method we define in the class will alter the internal state of the object according to the method definition and purpose. here initialize method does the same, such as creating a new instance variable.
var object = Foo.new(1)
#<Foo:0x00000001910cc0 #bar=1>
In the background, ruby has created an instance variable (#bar =1) and stored the value as state of the object inside the object 'object'. we can be able to check it with 'instance_variables' method and that methods returns an array containing all the instance variables of the object according to present state of the object.
object.instance_variables
#[
[0]: #bar
]
we can see '#bar' instance variable above. which is created when we called the initialize method on the object. this '#bar' variable should not be visible (hidden) by default and so it cannot be seen by others from outside of the object except the object, from inside. But, an object can mess around with its own internal state and this means it can show or change the values if we give it a way to do so, these two can be done by creating a new instance methods in the class.
when we want to see the #bar variable by calling it we get an error, as by default we cannot see the state of an object.
show = object.bar
#NoMethodError: undefined method `bar' for #<Foo:0x00000001910cc0 #bar=1>
#from (irb):24
#from /home/.rvm/rubies/ruby-2.0.0-p648/bin/irb:12:in `<main>'
But we can access the variables by two methods, these two are called setter and getter methods, which allow the object to show or change its internal state (instance variables/attributes/properties) respectively.
class Foo
def bar
#bar
end
def bar=(new_bar)
#bar = new_bar
end
end
We have defined a getter(bar) and setter(bar=) methods, we can name them any way but the instance variable inside must the same as instance variable to which we want to show or change the value. setters and getters are a violation to OOPS concepts in a way but they are also very powerful methods.
when we define the two methods by re-opening the class and defining them, when we call the object with the methods, we can be able to view the instance variables(here #foo) and change its value as well.
object.bar
1
object.bar=2
2
object.bar
2
Here we have called the bar method (getter) which returns the value of #bar and then we have called bar= method (setter) which we supplied a new_value as argument and it changes the value of instance variable (#bar) and we can look it again by calling bar method.
In ruby we have a method called attr_accessor , which combines the both setter and getter methods, we define it above the method definitions inside the class. attr_* methods are shortcut to create methods (setter and getter)
class Foo
attr_accessor :bar
end
we have to supply a symbol (:bar) as argument to the attr_accessor method which creates both setter and getter methods internally with the method names as supplied symbol name.
If we need only a getter method, we can call attr_reader :bar
If we need only a setter method, we can call attr_writer :bar
attr_accessor creates both attr_writer and attr_reader methods
we can supply as many instance variables as we want to the attr_* methods seperated by commas
class Foo
attr_writer :bar
attr_reader :bar
attr_accessor :bar, :baz
end
Because attr_accessor defines methods, you can call them from outside the class. A #variable is only accessible from inside the class.
And another answer more compact (for Java developers)
attr_accessor :x creates the getters and setters to #x
class MyClassA
attr_accessor :x
end
is the same as
class MyClassB
def x=(value) #java's typical setX(..)
#x=value
end
def x
#x
end
end
class MyClass
def instance_variable=(var)
puts "inside getter"
instance_variable = var
end
def function_1
self.instance_variable = "whatever"
end
def function_2
#instance_variable = "whatever"
end
end
myclass = MyClass.new
myclass.function1
results wiht "inside getter" on the console
myclass.function2
does not.
Im new to Ruby, do not know the difference, couldnt find it on the web...
Thanks in advance!
EDIT:
I assumed that by appending the "=", I overwrite a getter method for an implicitly defined instance variable "instance_variable."
That's also the reason why I called it that way.
Im not used to be allowed to use "=" in function names.
Thats why I assumed it would had some special meaning.
Thanks for your help.
EDIT2:
I just thought I really overwrite the assignment and not only the getter. I got it all mixed up.
Sorry and Thanks.
You have (misleading) named your setter instance_variable. It is not an instance variable, it is a method that sets an instance variable.
When you call self.instance_variable= you are calling that method. When you set #instance_variable directly you are setting the variable itself, and that is why the setter method is not called.
A more idiomatic naming convention would be something like:
def name=(value)
#name = value
end
Of course, for simply, pass-through type getters and setters you can use
attr_reader :name #generates getter only
attr_writer :name #generates setter only, not very common
attr_accessor :name #generates getter and setter
The above methods are syntactic sugar which generate the get and/or set methods for you. They can be overriden later to provide additional functionality if needed.
EDIT: I see that you have made an update and just wanted to point out that this method doesn't set an instance variable at all:
def instance_variable=(var)
puts "inside getter"
instance_variable = var
end
In this case instance_variable is simply a local variable and will be discarded as soon as the method exits. Local variables take precedence over instance methods, and instance variables always begin with a # symbol.
Let there be class Example defined as:
class Example
def initialize(test='hey')
self.class.send(:define_method, :say_hello, lambda { test })
end
end
On calling Example.new; Example.new I get a warning: method redefined; discarding old say_hello. This, I conclude, must be because it defines a method in the actual class (which makes sense, from the syntax). And that, of course, would prove disastrous should there be multiple instances of Example with different values in their methods.
Is there a way to create methods just for the instance of a class from inside that instance?
You need to grab a reference to the instance's singleton class, the class that holds all the instance specific stuff, and define the method on it. In ruby 1.8, it looks a little messy. (if you find a cleaner solution let me know!)
Ruby 1.8
class Example
def initialize(test='hey')
singleton = class << self; self end
singleton.send :define_method, :say_hello, lambda { test }
end
end
Ruby 1.9 however, provides a much easier way in.
Ruby 1.9
class Example
def initialize(test='hey')
define_singleton_method :say_hello, lambda { test }
end
end
First off, a small style tip:
self.class.send(:define_method, :say_hello, lambda { test })
You can make this look a little bit nicer by using the new proc literal in Ruby 1.9:
self.class.send(:define_method, :say_hello, -> { test })
But you don't need that. Ruby has something called blocks, which are basically a piece of code that you can pass as an argument to a method. In fact, you already used blocks, since lambda is just a method which takes a block as an argument and returns a Proc. However, define_method already takes a block anyway, there is no need to pass a block to lambda which converts it to a Proc which it passes to define_method which then converts it back into a block:
self.class.send(:define_method, :say_hello) { test }
As you already noticed, you are defining the method on the wrong class. You are defining it on the Example class, since inside an instance method like initialize, self is the current object (i.e. ex1 or ex2 in #mikej's example), which means that self.class is ex1's class, which is Example. So, you are overwriting the same method over and over again.
This leads to the following unwanted behavior:
ex1 = Example.new('ex1')
ex2 = Example.new('ex2') # warning: method redefined; discarding old say_hello
ex1.say_hello # => ex2 # Huh?!?
Instead, if you want a singleton method, you need to define it on the singleton class:
(class << self; self end).send(:define_method, :say_hello) { test }
This works as intended:
ex1 = Example.new('ex1')
ex2 = Example.new('ex2')
ex1.say_hello # => ex1
ex2.say_hello # => ex2
In Ruby 1.9, there's a method that does that:
define_singleton_method(:say_hello) { test }
Now, this works the way you want it to, but there's a higher-level problem here: this is not Ruby code. It is Ruby syntax, but it's not Ruby code, it's Scheme.
Now, Scheme is a brilliant language and writing Scheme code in Ruby syntax is certainly not a bad thing to do. It beats the hell out of writing Java or PHP code in Ruby syntax, or, as was the case in a StackOverflow question yesterday, Fortran-57 code in Ruby syntax. But it's not as good as writing Ruby code in Ruby syntax.
Scheme is a functional language. Functional languages use functions (more precisely, function closures) for encapsulation and state. But Ruby is not a functional language, it is an object-oriented language and OO languages use objects for encapsulation and state.
So, function closures become objects and captured variables become instance variables.
We can also come at this from a completely different angle: what you are doing is that you are defining a singleton method, which is a method whose purpose it is to define behavior which is specific to one object. But you are defining that singleton method for every instance of the class, and you are defining the same singleton method for every instance of the class. We already have a mechanism for defining behavior for every instance of a class: instance methods.
Both of these arguments come from completely opposite directions, but they arrive at the same destination:
class Example
def initialize(test='hey')
#test = test
end
def say_hello
#test
end
end
I know it was asked two years back, but I would like to add one more answer. .instance_eval will help to add methods to instance object
string = "String"
string.instance_eval do
def new_method
self.reverse
end
end
Define instance method from outside:
example = Example.new
def example.say_hello
puts 'hello'
end
From inside:
class Example
def initialize(word='hey')
#word = word
def self.say_hello
puts "example: #{#word}"
end
end
end
Tested on ruby 2.5