# Dynamic # of Attributes for a Model (key/val table) Get/Set?

**URL:** <https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350>\
**Category:** Rails\
**Created:** [December 5, 2006, 7:34am UTC](https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350 "2006-12-05T07:34:07Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![JSRiddel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/9fc348/32.png) [@JSRiddel](https://www.ruby-forum.com/u/JSRiddel)\
**Post date:** [December 5, 2006, 7:34am UTC](https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350/1 "2006-12-05T07:34:07Z")

</div>

I’m working on a simple product catalog. Products have user defined  
attributes, such as: color, size, weight. More attributes can be added  
at any time. Since these attributes are not known ahead of time, they  
cannot be created as columns.

My table structure (simplified):

## products

id  
name

## attrs

id  
name

## product\_attrs

id  
attr\_id  
value

And some sample code:

## Create some attributes

## 1 - size

## 2 - color

## 3 - weight

[‘size’,‘color’,‘weight’].each do |attr|  
Attr.create( { ‘name’ =\> attr } )  
end

## Create a new product

p = Product.new( { ‘name’ =\> ‘Widget’ } )

## Assign some attributes

p.product\_attrs \<\< ProductAttr.create( { ‘attr\_id’ =\> 1 } ) # size  
p.product\_attrs \<\< ProductAttr.create( { ‘attr\_id’ =\> 2 } ) # color  
p.product\_attrs \<\< ProductAttr.create( { ‘attr\_id’ =\> 3 } ) # weight

## Output

p.product\_attrs.collect{ |product\_attr| product\_attr.name } =\> [size,  
color, weight]

## Product ‘p’ now has 3 ProductAttributes associated with it (which in

turn are associated with the three attributes [size, color, weight]  
created above)

Now that the product has associated attributes – I’d like an easy way  
to get and set their values. Is there any way to do something like:

p.product\_attrs[‘color’] = ‘red’  
-or-  
p.product\_attrs.color = ‘red’

Right now, the only way I’ve gotten this to work is with:

p.product\_attrs.find( Attr.find\_by\_name(‘color’) ).value = ‘red’

…which isn’t all that nice looking. I could probably hack something  
up, but I figure I’d ask first.

Maybe I’m even on the wrong path here and somebody else has a clue as to  
how I can organize this data all together. Is there an ideal way of  
handling a dynamic number of Model attributes with (or without) using a  
key/value type table structure as I describe above (The ‘attributes’  
table defines the key, the ‘product\_attributes’ defines the value).

Best,  
J

---

<div class="post-metadata">

**Author:** ![JSRiddel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/9fc348/32.png) [@JSRiddel](https://www.ruby-forum.com/u/JSRiddel)\
**Post date:** [December 5, 2006, 8:08am UTC](https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350/2 "2006-12-05T08:08:23Z")

</div>

On 12/5/06, J. Riddel [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I’m working on a simple product catalog. Products have user defined  
> attributes, such as: color, size, weight. More attributes can be added  
> at any time. Since these attributes are not known ahead of time, they  
> cannot be created as columns.

## Assign some attributes

> p.product\_attrs \<\< ProductAttr.create( { ‘attr\_id’ =\> 1 } ) # size  
> p.product\_attrs \<\< ProductAttr.create( { ‘attr\_id’ =\> 2 } ) # color  
> p.product\_attrs \<\< ProductAttr.create( { ‘attr\_id’ =\> 3 } ) # weight
> 
> …which isn’t all that nice looking. I could probably hack something  
> up, but I figure I’d ask first.

I would start with creating some collection class, that will allow using  
indexers (or even through method\_missing) to access product’s custom  
attributes. Something like that:

my\_product.attrs[:size] or my\_product.attrs.size

It is easy: instantiate collection class and pass product id to it. Then  
when you try to access some attributes, just do ProductAttr.find( yada  
yada  
) to get attribute value.

After that you could think even further and implement custom attributes  
interception in Product’s method\_missing (to allow my\_product.size).

---

<div class="post-metadata">

**Author:** ![JSRiddel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/9fc348/32.png) [@JSRiddel](https://www.ruby-forum.com/u/JSRiddel)\
**Post date:** [December 5, 2006, 4:05pm UTC](https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350/3 "2006-12-05T16:05:25Z")

</div>

J. Riddel wrote:

> I’m working on a simple product catalog. Products have user defined  
> attributes, such as: color, size, weight. More attributes can be added  
> at any time. Since these attributes are not known ahead of time, they  
> cannot be created as columns.

Let me suggest I a plugin I have created for this purpose.

[https://rubyforge.org/projects/flex-attributes/](https://rubyforge.org/projects/flex-attributes/)

The plugin is still in “beta” since the application it is made for has  
not been rolled out to production but it seems to work well.

Basically your model looks something like:

class Product \< ActiveRecord::Base  
has\_flex\_attributes  
end

Then you can just add/remove attributes as you need. If the attribute  
exists on the model it will be stored there. If it does not then it will  
be stored in a “thin” table called product\_attributes.

There are also hooks so you can define what attributes are valid.  
Finally the plugin works with  
acts\_as\_versioned/acts\_as\_versioned\_association.

The docs are a little scattered right now because the product it was  
created for is still in development but you are welcome to use what I  
have.

Eric

---

<div class="post-metadata">

**Author:** ![JSRiddel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/9fc348/32.png) [@JSRiddel](https://www.ruby-forum.com/u/JSRiddel)\
**Post date:** [December 5, 2006, 7:47pm UTC](https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350/4 "2006-12-05T19:47:40Z")

</div>

J. Riddel wrote:

> > Let me suggest I a plugin I have created for this purpose.
> > 
> > [https://rubyforge.org/projects/flex-attributes/](https://rubyforge.org/projects/flex-attributes/)
> 
> I came up with a solution using MethodMissing, but your plugin looks to  
> be what I need. However, there is nothing to download from that link?  
> Can you add the files?
> 
> J

Nevermind, it was in SVN. RubyForge just showed that it had 0 CVS and  
SVN commits.

---

<div class="post-metadata">

**Author:** ![JSRiddel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/9fc348/32.png) [@JSRiddel](https://www.ruby-forum.com/u/JSRiddel)\
**Post date:** [December 5, 2006, 7:44pm UTC](https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350/5 "2006-12-05T19:44:36Z")

</div>

> Let me suggest I a plugin I have created for this purpose.
> 
> [https://rubyforge.org/projects/flex-attributes/](https://rubyforge.org/projects/flex-attributes/)

I came up with a solution using MethodMissing, but your plugin looks to  
be what I need. However, there is nothing to download from that link?  
Can you add the files?

J

---

<div class="post-metadata">

**Author:** ![JSRiddel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/9fc348/32.png) [@JSRiddel](https://www.ruby-forum.com/u/JSRiddel)\
**Post date:** [December 5, 2006, 8:01pm UTC](https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350/6 "2006-12-05T20:01:52Z")

</div>

Eric –

Thanks a lot. This works great. Slightly different than what I came up  
with (in 10 lines with MethodMissing), but it “feels” better and  
actually makes my relationship less complicated. Thanks a lot. Great  
timing.

J

---

<div class="post-metadata">

**Author:** ![JSRiddel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/9fc348/32.png) [@JSRiddel](https://www.ruby-forum.com/u/JSRiddel)\
**Post date:** [December 5, 2006, 8:48pm UTC](https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350/7 "2006-12-05T20:48:30Z")

</div>

J. Riddel wrote:

> Thanks a lot. This works great. Slightly different than what I came up  
> with (in 10 lines with MethodMissing), but it “feels” better and  
> actually makes my relationship less complicated. Thanks a lot. Great  
> timing.

Glad it is working for you. The plugin started out simple but I needed  
to also support acts\_as\_versioned (so the related attributes are  
versioned) which made the plugin much more complicated.

If you (or anybody that uses this plugin) get any problems send me a  
message. It is fairly new (the site it was developed for hasn’t even hit  
production yet) so there may be some issues with it still.

Eric

---

<div class="post-metadata">

**Author:** ![JSRiddel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/9fc348/32.png) [@JSRiddel](https://www.ruby-forum.com/u/JSRiddel)\
**Post date:** [December 6, 2006, 3:25am UTC](https://www.ruby-forum.com/t/dynamic-of-attributes-for-a-model-key-val-table-get-set/78350/8 "2006-12-06T03:25:35Z")

</div>

Good idea, I’ll take a look at it as well.
