What would a default getter and setter look like in rails?
attr_accessor
is a built-in Ruby method and has no special meaning in the context ActiveRecord. attr_accessor :tag_list
is basically equivalent to this code:
# getter
def tag_list
@tag_list
end
# setter
def tag_list=(val)
@tag_list = val
end
In ActiveRecord models, however, it could be that you want something like this:
def tag_list
self[:tag_list]
end
def tag_list=(val)
self[:tag_list] = val
end
There is a slight difference: With the first method, obj[:tag_list]
doesn't use the same storage as your getter and setter. With the latter, it does.
Explanation of the getter/setter concept
In Ruby, the following two lines of code are equivalent
thing.blabla
thing.blabla()
Both call the method blabla
of the object thing
and evaluate to the last expression evaluated within that method. This means, you also don't need a return
statement in the case of the above getter method, because the method simply returns the last expression in the method (@tag_list
, the value of the instance variable).
Also, those two lines of code are equivalent:
thing.blabla=("abc")
thing.blabla = "abc"
Both call the method blabla=
of the object thing
. The special name with the =
character can be used like any other method name.
The fact that attributes, as they are sometimes called, are in fact plain methods, you can also use some special logic transformed on the values before returning or accepting them. Example:
def price_in_dollar
@price_in_euro * 0.78597815
end
def price_in_dollar=(val)
@price_in_euro = val / 0.78597815
end
Ruby/Rails: Understanding ruby getter-setter methods and instances
When you do
@dog = Dog.new
You do two spearate things
1) Create an instance variable @dog for whatever object your code is currently inside
2) Instantiate a new instance of Dog (with all its methods and attributes) and assign a reference to it to @dog
@dog is a variable, that just happens to point at the Dog instance ("instance of class" generally same meaning as "object") you created at that point. You can set other variables to point to the same instance, and in Ruby this is generally how you pass data around. Objects contain instance variables, and those instance variables point to yet more objects.
Using the assignment operator (i.e "=") you can point a variable at any other object.
To answer your questions in turn:
When I am in the owner class and I call @dog.popularity how does it
know the value of popularity for that instance?
You have to be careful in Ruby (and OO languages in general) to differentiate between class and object in your descriptions and questions. Ruby I'm assuming you are referring to a line of code in the Owner class, and that you intend it to work with an owner object. I'd also assume that @dog is an attribute you have added to Owner.
In which case, Ruby knows because @dog points to the Dog object that you added to owner. Each Dog object has its own copy of all of Dog's instance variables. You do need to take care in Ruby though, because variables point to objects, that you aren't simply passing in the same Dog object to all the owners (i.e. they all effectively share a single dog). So you need to understand when you are creating new instances (via new) and when you are simply handling existing references.
At runtime are all methods processed and then that instance just
always is tied to the value at the time?
No. At runtime, basic Ruby will only perform the assignments that you have coded. Instance variables may not even exist until the code that assigns them has been run. If you use attr_reader etc methods, then the variables will at least exist (but will be nil unless you assign something during initialize)
Calling setters and getters
In your example:
book01.isbn=("9876")
book01.isbn= "9876"
book01.isbn = "9876"
The last 2 examples are 'syntactic sugar', which are things that technically aren't proper syntactically but are kept in the language because they keep the code cleaner. The first example is the only way that would work if Ruby didn't support syntactic sugar. Why?
Because attr_acccessor :isbn behind the hood creates the following code for you:
def isbn
@isbn
end
def isbn=(new_isbn)
@isbn = new_isbn
end
These are 2 totally different methods, this might be confusing because the only difference in name is the = sign. But that doesn't mean anything, and doesn't change the fact they are totally different methods.
So with:
book01.isbn=("9876")
you're actually calling def isbn=(new_isbn) which is a method, nothing more, nothing else. And with:
book01.isbn= "9876"
book01.isbn = "9876"
you're just calling the SAME method, just using 'syntactic sugar'. Behind the hood, Ruby sees all of these 2 as:
book01.isbn=("9876")
Can you guess why this code will not work?
book01.isbn("9876")
Because, as we saw earlier, behind the hood Ruby creates 2 methods. The first method doesn't accept ANY arguments, therefore, you get the error you're getting (Ruby is just telling you, I expected 0 arguments, and you provided 1, therefore I raised ArgumentError).
Im trying to understand Getters and Setters in the ruby programming language
Understanding attr_accesor, attr_reader and attr_writer
These are Ruby's getters and setters shortcut. It works like C# properties, that injects the get_Prop
(getter) and set_Prop
(setter) methods.
attr_accessor
: injectsprop
(getter) andprop=
(setter) methods.attr_reader
: it's a shortcut for read-only properties. Injectsprop
method. Theprop
value can only be changed inside the class, manipulating the instance variable@prop
.attr_writer
: it's a shortcut for write-only properties. Injectsprop=
method.
Ruby doesn't have methods called get_prop
(getter) and set_prop
(setter), instead, they're called prop
(getter) and prop=
(setter).
That being said, you can infer that
class Person
attr_accessor :name, :age
end
is the short version for
class Person
# getter
def name
return @name
end
# setter
def name=(value)
@name = value
end
end
You don't need to call return
, Ruby methods returns the last executed statement.
If you are using Ruby on Rails gem, you can build model objects using new
and passing properties values as arguments, just like:
p = Person.new(name: 'Vinicius', age: 18)
p.name
=> 'Vinicius'
That's possible because Rails injects something like this initialize
method to ActiveRecord::Base
and classes that includes ActiveModel::Model
:
def initialize(params)
params.each do |key, value|
instance_variable_set("@#{key}", value)
end
end
Ruby add getters and setters without def?
Ruby let you define simple getters/setters using the methods attr_accessor
, attr_reader
, and attr_writer
. In your example you can use attr_accessor
to define both a getter and a setter for your instance variables:
class Book
attr_accessor :title, :author, :pages, :year
def initialize (title, author, pages, year)
# same as before...
end
end
book = Book.new('foo', 'bar', 100, 2010)
book.title
# => "foo"
book.title = 'baz'
book.title
# => "baz"
Calling attr_accessor :title
is equivalent to define a couple of methods like the following:
def title
@title
end
def title=(new_title)
@title = new_title
end
You can find more informations about assignment methods (i.e. methods whose name end in =
) on the Ruby documentation.
Do Ruby objects have a built in getter/setter methods?
You're looking for attr_accessor :color
if you want just the run of the mill auto-generated getters/setters.
Defines a named attribute for this module, where the name is symbol.id2name, creating an instance variable (@name) and a corresponding access method to read it. Also creates a method called name= to set the attribute. String arguments are converted to symbols.
There's also just an attr_reader :color
if you don't want to be able to set the value outside the class
Creates instance variables and corresponding methods that return the value of each instance variable.
And attr_writer :color
if you want to set, but not read, outside of the class.
Creates an accessor method to allow assignment to the attribute.
class Obj
attr_accessor :color
def initialize(color)
@color = color
end
end
t = Obj.new("red")
t.color #=> "red"
Ruby get and set in one method
The trickier case is if you want to set duration to nil. I can think of two ways of doing this
def duration(*args)
@duration = args.first unless args.empty?
@duration
end
Allow people to pass any number of args and decide what to do based on the number. You could also raise an exception if more than one argument is passed.
Another way is
def duration(value = (getter=true;nil))
@duration = value unless getter
@duration
end
This exploits default arguments a little: they can be pretty much any expression.
When called with no arguments getter
is set to true, but when an argument is supplied (even if it is nil) the default value is not evaluated. Because of how local variable scope works getter
ends up nil.
Possibly a little too clever, but the method body itself is cleaner.
Trying to learn / understand Ruby setter and getter methods
You can interact with that instance variable from other methods belonging to that instance, even if there is no getter:
def noise=(noise)
@noise = noise
end
def last_noise
@noise
end
There doesn't need to be a getter defined with the same name as the method; the two are not linked at all. The getter is needed to "get" the value of the instance variable, but only in a short syntax.
What's happening in your example is that you're initializing a new object (Human.new
), and then using a method (noise=
, yes the method name contains the =
symbol) that just-so-happens to define an instance variable (that is, a variable just for that instance), and then finally retrieving that instance variable with another method call.
You can actually use instance_variable_get
to get the instance variable without defining any getter at all:
man = Human.new
man.noise = "Howdie"
man.instance_variable_get("@noise")
This will return "Howdie", even though there is no getter defined.
And no, I don't think he's using an older version of Ruby.
Related Topics
Naming Boolean Columns in Rails
Rails: Opposite of Hash#To_Param
Rails - Get the Time Difference in Hours, Minutes and Seconds
Why Is Ruby Unable to Verify an Ssl Certificate
Ruby Code to Extract Host from Url String
Printing Qr Codes Through an Esc/Pos Thermal Printer
Passing Headers and Query Params in Httparty
How to Specify Output File Encoding in Ruby
Undef - Why Would You Want to Undefine a Method in Ruby
How Does Rails Csrf Protection Work
Heroku Rails 4 Could Not Connect to Server: Connection Refused
Convert Non-Breaking Spaces to Spaces in Ruby
Ruby: What's the Difference Between Stdin.Gets() and Gets.Chomp()
How to Set/Get Session Vars in a Rack App
How to Sort a String's Characters Alphabetically
Are Rails Controllers Multithreaded? Thread.Exclusive in Controllers