14

In PHP, I can set an attribute (that is not a column in database) to a model. E.g.(PHP code),

$user = new User; $user->flag = true; 

But in rails, when I set any attribute that doesn't exist in database, it will throw an error undefined method flag. There is attr_accessor method, but what will happen if I need about ten temp attributes?

5
  • Having non column attributes in the object is a code smell, at least for me. Here something related: youtube.com/watch?v=SvL_aZt3zyU Commented Dec 22, 2015 at 11:17
  • 1
    You wouldn't normally use $-variables in rails. Are you mixing php and ruby code together there? Commented Dec 22, 2015 at 11:23
  • @MaxWilliams No, that is a PHP example. Commented Dec 22, 2015 at 11:24
  • Oh, so you're saying "How do i do this in rails?"? That's not clear, to me at least. Commented Dec 22, 2015 at 11:26
  • @MaxWilliams oh, I'm sorry because make the example not clear Commented Dec 23, 2015 at 3:58

5 Answers 5

22

but what will happen if I need about ten temp attributes?

#app/models/user.rb class User < ActiveRecord::Base attr_accessor :flag, :other_attribute, :other_attribute2, :etc... end 

attr_accessor creates "virtual" attributes in Rails -- they don't exist in the database, but are present in the model.

As with attributes from the db, attr_accessor just creates a set of setter & getter (instance) methods in your class, which you can call & interact with when the class is initialized:

#app/models/user.rb class User < ActiveRecord::Base attr_accessor :flag # getter def flag @flag end # setter def flag=(val) @flag = val end end 
Sign up to request clarification or add additional context in comments.

Comments

4

This is expected because it's how ActiveRecord works by design. If you need to set arbitrary attributes, then you have to use a different kind of objects.

For example, Ruby provides a library called OpenStruct that allows you to create objects where you can assign arbitrary key/values. You may want to use such library and then convert the object into a corresponding ActiveRecord instance only if/when you need to save to the database.

Don't try to model ActiveRecord to behave as you just described because it was simply not designed to behave in that way. That would be a cargo culting error from your current PHP knowledge.

1 Comment

thank a lot, I never know OpenStruct lib until you told me. I combined your solution with @Nimir solution and it work perfectly :D attr_accessor :flag after_initialize do |user| self.flag = OpenStruct.new end And I can set/get the temp flag attribute by using @user.flag.hello = "Hello World" ps: sr, I don't know how to format the code
3

As the guys explained, attr_accessor is just a quick setter and getter.

We can set our Model attr_accessor on record initializing to be a Ruby#Hash for example using ActiveRecord#After_initilize method so we get more flexibility on temporarily storing values (idea credit to this answer).

Something like:

class User < ActiveRecord::Base attr_accessor :vars after_initialize do |user| self.vars = Hash.new end end 

Now you could do:

user = User.new #set user.vars['flag'] = true #get user.vars['flag'] #> true 

Comments

2

All that attr_accessor does is add getter and setter methods which use an instance variable, eg this

attr_accessor :flag 

will add these methods:

def flag @flag end def flag=(val) @flag = val end 

You can write these methods yourself if you want, and have them do something more interesting than just storing the value in an instance var, if you want.

Comments

0

If you need temp attributes you can add them to the singleton object.

instance = Model.new class << instance attr_accessor :name end 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.