Leem.fin
Leem.fin

Reputation: 42602

a way to have an model attribute which is not persist in database as a table column

I am using Rails v2.3.2.

I have a model:

class Cars < ActiveRecord::Base

  tag_nr = rand(2007)

end

The Cars model is mapped to the cars table in database with columns name, owner.

As you see above, there is also a tag_nr which is basically a random number.

I would like to have each instance object of Cars class hold a random number generated like above. But I do not want to have this random number be stored in database. And in future, I can access this instance object's tag_nr by:

nr = CAR_INSTANCE.tag_nr

And the nr now is the same as the tag_nr first generated for this Cars instance object.

So, where and how should I define this random number in my Car model?

-----------What I tried is:-----------

class Cars < ActiveRecord::Base
  after_initialize :init

  attr_accessor :tag_nr

  def init
    @tag_nr = rand(2007)
  end
end  

But if I retrieve a car from database and try to access tag_nr, I got nil:

@c=Cars.first
@c.tag_nr.nil? # it returns true

So, how can I have an model attribute(like tag_nr) which is not persist in database as a table column but can be accessed as an attribute?

Upvotes: 1

Views: 1785

Answers (4)

Pasted
Pasted

Reputation: 864

Shouldn't that be

class Cars < ActiveRecord::Base
  after_initialize :init

  attr_accessor :tag_nr

  def init
    self.tag_nr = rand(2007)
  end
end

Example output from a Drug model (just because it was what I was working on at the time)

> d = Drug.first

=> #<Drug id: 1, name: "NSAIDs", category: "NSAID", comment: "Non-steroidal anti-inflammatory", created_at: "2011-11-23 17:46:22", updated_at: "2011-11-23 17:46:22">

> d.tag_nr

=> 1069

> d = Drug.last

=> #<Drug id: 6, name: "Antihypertensives", category: "ANTIHYPERTENSIVE", comment: "", created_at: "2011-11-23 17:46:22", updated_at: "2011-11-23 17:46:22">

> d.tag_nr

=> 1838

> d = Drug.first

=> #<Drug id: 1, name: "NSAIDs", category: "NSAID", comment: "Non-steroidal anti-inflammatory", created_at: "2011-11-23 17:46:22", updated_at: "2011-11-23 17:46:22">

> d.tag_nr

=> 800

There is nothing to stop a collision between the random numbers (ie two different instances could return the same number).

Upvotes: 0

Bohdan
Bohdan

Reputation: 8408

I suppose this task can't be solved. As I understand you want next: you have a Car in your DB and

car = Car.find(10)
car.tag_nr         # assume this expression returns 100
...                # some code here
other_car = Car.find(10)
car.tag_nr         # this expression returns 100

correct?

if yes you have to pay more attention to = operator which createc new object each time you use it you can check it with object_id

irb(main):074:0> "abs".object_id
=> 21413208
irb(main):075:0> "abs".object_id
=> 20742936
irb(main):076:0> a = "abs"
=> "abs"
irb(main):077:0> a.object_id
=> 21493488
irb(main):078:0> a = "abs"
=> "abs"
irb(main):079:0> a.object_id
=> 21172272

since all objects are different they have different values for instance variables

Upvotes: 0

Taryn East
Taryn East

Reputation: 27747

The problem with what you need is in the part where you say you want to be able to access the same random number over and over again.

You're asking for this number to persist, even though you're wanting to not store it in the database...

Either information persists... or it doesn't. Information that persists must be stored somewhere. Currently your persistent data is stored in the database.

You can see the problem here, I hope.

Any number you generate will last only so long as the object lasts... ie for the duration of a single request/response... and then it will disappear, because you are not persisting it in the place where data is persisted (the database).

If single-response duration is all that's need, then the solutions already offered here are the best you can get.

The alternatives are:

  1. store it in the db (it's the only way to be sure)
  2. find some way of hashing on a unique-and-non-changable aspect of the data in your model. eg run MD5 or SHA1 over the records id+created_at timestamp

Upvotes: 4

Rym
Rym

Reputation: 650

Try this:

class Cars < ActiveRecord::Base
  extend ActiveSupport::Memoizable

  def tag_nr
    rand(2007)
  end
  memoize :tag_nr
end

from: http://rails-bestpractices.com/posts/59-use-memoization

Upvotes: 2

Related Questions