Rails, Activerecord: Self[:Attribute] VS Self.Attribute

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 scope
  • a_user.email when you have specified a user
  • email when you are in the User class. This is valid for every method in the User class.
  • @email, the variable returned by the email function
  • attributes[: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



Leave a reply



Submit