# Arbitrary "Columns" for ActiveRecord

**URL:** <https://www.ruby-forum.com/t/arbitrary-columns-for-activerecord/102228>\
**Category:** Rails\
**Created:** [August 13, 2006, 12:40pm UTC](https://www.ruby-forum.com/t/arbitrary-columns-for-activerecord/102228 "2006-08-13T12:40:23Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rick\_Martinez](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f19dbf/32.png) [@Rick\_Martinez](https://www.ruby-forum.com/u/Rick_Martinez)\
**Post date:** [August 13, 2006, 12:40pm UTC](https://www.ruby-forum.com/t/arbitrary-columns-for-activerecord/102228/1 "2006-08-13T12:40:23Z")

</div>

I’m having a bit of a tough time coming up with a good solution for what  
I’m trying to do. I’ve come up with a couple of solutions that work  
pretty well but many use way too many queries or are just not very good.

Basically I want to store something of a property list for a model.

class Model \< AR  
has\_many :properties, :dependent =\> :delete  
end

class Property \< AR  
belongs\_to :model  
belongs\_to :property\_key  
end

|------------------

| properties |
| --- |
| id (serial) |
| value (varchar) |
| property\_key\_id (int) |
| model\_id (int) |
| ------------------ |

Now an issue is that I also store possible KEYs for my properties.

class PropertyKey \< AR  
has\_many :properties, :dependent =\> :delete  
end

|-----------------

| property\_keys |
| --- |
| id (serial) |
| key (varchar) |
| ----------------- |

I’d like to access a model’s properties somewhat like:

Model.property\_key = value # where property\_key is dynamic/magic

OR

Model.get\_property(key, value)

The problem here is, that with this set up, the way I have it set up, I  
have Model#get\_property set to this:

def get\_property(key)  
if key = PropertyKey.find\_by\_key(key)  
self.properties.find(:first, :condition =\> [“property\_key\_id = ?”,  
key.id]).value  
else  
false  
end  
end

and Model#set\_property

def set\_property(key, value)  
if row = properties.find(:first, :conditions =\> [“properties.key = ?”,  
key], :include =\> :property\_key)  
if value.empty?  
return row.destroy  
else  
row.value = value  
return row.save  
end  
else  
key = PropertyKey.find\_by\_key(key)  
properties \<\< Property.new(:key =\> key, :value =\> value) unless  
value.empty?  
end  
end

This is what I have so far. Any help at all would be greatly appreciated  
in optimizing this code and making it better! Thanks!!

---

<div class="post-metadata">

**Author:** ![Rick\_Martinez](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f19dbf/32.png) [@Rick\_Martinez](https://www.ruby-forum.com/u/Rick_Martinez)\
**Post date:** [August 15, 2006, 2:19pm UTC](https://www.ruby-forum.com/t/arbitrary-columns-for-activerecord/102228/2 "2006-08-15T14:19:24Z")

</div>

Rick Martinez wrote:

> I’m having a bit of a tough time coming up with a good solution for what  
> I’m trying to do

im not clear on what youre trying to do. do you want static models like  
the  
symbiotic db-schema/model.rb relationship dictates? if so, and you just  
want  
to decorate records with the occasional extra attribute, a serialized  
hash  
may do the trick (as ezra offers).

in any case, rails has already taken a SQL result hash and ‘objectized’  
it.  
to treat that object as a generic ‘Model’ or ‘Property’ class again,  
then  
layer dynamic properties on top of this again, results in a loss of 2  
things: performance and magic…

ie, a model with 5 columns besides the id can go from 1 query to 6. and  
Model.find\_by\_property() will no longer work, nor will you get free  
setter/getter methods, unless you add them back via either rewriting  
portions of activerecord or providing your own additional  
method\_missings.

> This is what I have so far. Any help at all would be greatly

i’d consider how important model refactorability and schema dynamism is  
to  
your application. if it is important, i’d consider swapping out  
ActiveRecord  
for Redland, ActiveRDF, or something custom built on eg BerkeleyDB,  
perhaps  
bypassing the ‘objectification’ process entirely and sticknig with a  
generic  
‘Resource’ class but eliminating the abuse of an ActiveRecord class for  
this  
purpose…

–  
View this message in context:  
[http://www.nabble.com/Arbitrary-"Columns"-for-ActiveRecord-tf2098713.html#a5789846](http://www.nabble.com/Arbitrary-%22Columns%22-for-ActiveRecord-tf2098713.html#a5789846)  
Sent from the RubyOnRails Users forum at [Nabble.com](http://Nabble.com).

---

<div class="post-metadata">

**Author:** ![Rick\_Martinez](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/f19dbf/32.png) [@Rick\_Martinez](https://www.ruby-forum.com/u/Rick_Martinez)\
**Post date:** [August 15, 2006, 2:20pm UTC](https://www.ruby-forum.com/t/arbitrary-columns-for-activerecord/102228/3 "2006-08-15T14:20:43Z")

</div>

On Aug 13, 2006, at 3:40 AM, Rick Martinez wrote:

> I’m having a bit of a tough time coming up with a good solution for  
> what  
> I’m trying to do. I’ve come up with a couple of solutions that work  
> pretty well but many use way too many queries or are just not very  
> good.
> 
> Basically I want to store something of a property list for a model.

Hey Rick-

```
Not sure if this is exactly what you would need but it might get you

```

going in the right direction.

class DbHash \< ActiveRecord::Base  
class \<\< self  
def   
pair = find\_by\_key(key.to\_s)  
pair.value unless pair.nil?  
end

```
 def []=(key, value)
   pair = find_by_key(key)
   unless pair
     pair = new
     pair.key, pair.value = key.to_s, value
     pair.save
   else
     pair.value = value
     pair.save
   end
   value
 end

 def to_hash
   Hash[*find_all.map { |pair| [pair.key, pair.value] }.flatten ]
 end

```

end  
end

```
 create_table "configurations", :force => true do |t|
   t.column "key", :string, :limit => 40, :default => "", :null

```

=\> false  
t.column “value”, :string, :default =\> “”  
end

```
You could add a foreign key or even go polymorphic to get this to

```

relate to your other models. But the way it is right here it will  
just act like a hash that is backed by the db.

-Ezra
