Rails, activerecord: self[:attribute] vs self.attribute
They're both just methods to get to the attribute - they're both just getters. self.attribtue
is a more "traditional" getter, whereas self[:attribute]
is basically just the []
method. Switching between using either has no ramifications.
I'd recommend using only the self.attribute
method because it's syntactically nicer. However, using the self[:attribute]
can come in handy when something else overrides the self.attribute
method.
For example, suppose you have a User model with a name
database column, so you'd get user.name
. But let's say you install a gem that adds a #name
method to each of your models. To avoid the complication, one option is to use user[:name]
to access it directly without going through the compromised method.
What's the difference between using self.attribute and attribute in a model?
The difference in your examples is that the first one works, the second doesn't.
Your second version isn't doing anything (at least nothing meaningful). Writing my_attr = 123
is not equivalent to self.my_attr = 123
. Instead it's creating a local variable called my_attr
and setting it to 123
, and then immediately reaching the end of the method and throwing my_attr
away. The whole method is essentially a no-op, and it doesn't affect the model's my_attr
value in any way.
class User < ActiveRecord::Base
def do_another_thing!
my_attr = 456
puts self.my_attr # nil (or whatever value it was before)
end
end
Conversely, if you want to access a method defined on an object, you can (and should) omit self
:
class User
def name=(value)
@name = value
end
def name
@name
end
def age=(value)
@age = value
end
def age
@age
end
def do_something
self.name = "bob" # self is required
puts name # bob (self.name)
age = 47 # @age is unaffected
age # 47 (local variable), but self.age is nil
end
end
Note that, this isn't a Rails question, it's a Ruby question. There is no Rails-specific code here, this behaviour is part of how Ruby's syntax works.
Is it better practice to use attribute_name or self.attribute_name when accessing within model
Camp 1: Convention over configuration. Also, self.first_name
will not work for private accessors.
Camp 2: You know what's what at a glance, whereas you might forget what methods you have without the explicit receiver.
In the end, it's an opinion question, so I'm voting to close. However, food for thought:
bbatsov style guide:
Avoid
self
where not required. (It is only required when calling a self write accessor.)
GitHub style guide (based on bbatsov style guide):
Avoid explicit use of
self
as the recipient of internal class or instance messages unless to specify a method shadowed by a variable.
Difference between self.attribute_name and only attribute_name
You can access email from different ways when you are on the User class.
self.email
when you are in the User scopea_user.email
when you have specified a useremail
when you are in the User class. This is valid for every method in the User class.@email
, the variable returned by theemail
functionattributes[:email]
the ActiveRecord attribute.
All of this methods are automatically generated by the ActiveRecord model, you can see the doc for more details.
Rails 4.2.5.1 ActiveRecord : When/Why does one use self[:attr]= in place of write_attribute()
If you look at the source on github, you can see that internally it uses the private method write_attribute_with_type_cast
:
https://github.com/rails/rails/blob/8fdd4bf761b280126e52a212eed187391bdedbb3/activerecord/lib/active_record/attribute_methods/write.rb#L55
This gives you one advantage over just calling self[:attribute]=value
yourself in that if you're setting id
, or what you think should be id
, the method will handle finding the correct attribute name of the primary key for your model.
Finally, through write_from_user
, rails actually calls self[:attribute] = value
for you, albeit with different names for things:
https://github.com/rails/rails/blob/8fdd4bf761b280126e52a212eed187391bdedbb3/activerecord/lib/active_record/attribute_set.rb#L38
Beyond the auto-correction of :id
to :custom_primary_key
if your model isn't using the standard id
column as its primary key, there is no functional advantage to using write_attribute
over self[:attribute]=value
.
How to read attribute only if it is present?
I agree with Ishank but you can call super
to use Rails' getter and then use ActiveSupport's presence
method which will return the value if it is present?
or otherwise return nil
(which will trigger the statement after the ||
).
def name
super.presence || "[You have no name yet]"
end
To be clear, stack level too deep is happening because you are checking self.name.blank?
- when you use self.name
here, that is calling the name
method on self (which is the method you are currently in) - so that results in an infinite loop.
Rails - Can't create a record that has an attribute with the same name of the class
I found the solution: use methods using self[:attribute], to be sure the attribute is accessed
#tax_scale model
def current_period
self[:period]
end
def current_period=(p)
self[:period] = p
end
#new.html.haml
= f.label :current_period
= f.number_field :current_period
Notice I have to use self[:period] and not self.period, because the second one is still accessing the parent record, not the attribute.
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.
ruby syntax (rails models)
Rails creates those model attributes as accessors which dynamically creates the methods for getting/setting the value. Its fun to use in your own classes as well, have a look here: http://ruby-doc.org/core/Module.html#method-i-attr_accessor
Related Topics
Rails/Rspec: How to Test #Initialize Method
<Rubygems> How to Change Gem Environment Settings
Ruby/Ror: Calling Original Method via Super()
Testing a Concern/Module That Uses Activerecord
Rails Can't Login to Postgresql - Pg::Error - Password - Correct Info
How to Authorize a Google Service Account Without the Default Credentials File
Find Memory Leak in a Ruby on Rails Project
Using Ruby, Reading a File, Containing Name/Value Pairs into a Hash
Stylesheet_Link_Tag :All Versus :Media =>All
Adding Keywords to Ruby Syntax Highlighting for Notepad++
Active Admin Scopes for Each Instance of a Related Model
How to Get the Version from a Gemspec File
Changing Active Model Serializers Default Adapter
How to Create a List of Months Between Two Dates in Rails
Removing Child Root Nodes in Rabl
What Are the Conventional Gem Paths for Ruby Under Os X 10.5
How to Instruct Capistrano 3 to Load My Shell Environment Variables Set at Remote Host