# Extending ActiveModel to handle multiple tables as hash

**URL:** <https://www.ruby-forum.com/t/extending-activemodel-to-handle-multiple-tables-as-hash/65712>\
**Category:** Rails\
**Created:** [August 20, 2006, 7:25pm UTC](https://www.ruby-forum.com/t/extending-activemodel-to-handle-multiple-tables-as-hash/65712 "2006-08-20T19:25:07Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Mage](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6f9a4e/32.png) [@Mage](https://www.ruby-forum.com/u/Mage)\
**Post date:** [August 20, 2006, 7:25pm UTC](https://www.ruby-forum.com/t/extending-activemodel-to-handle-multiple-tables-as-hash/65712/1 "2006-08-20T19:25:07Z")

</div>

Hello,

I am just introducing myself to Rails. Please let me know if the above  
method is acceptable or if it is not efficient.

I have three tables:

create table users (  
id bigserial primary key,  
username varchar,  
password varchar,  
– more system specific data  
);

create table user\_data\_types (  
id bigserial primary key,  
name varchar,  
code varchar,  
restriction varchar  
);

create table user\_data\_fields (  
id bigserial primary key,  
user\_id bigint not null references users(id) on delete cascade,  
user\_data\_type\_id bigint not null references user\_data\_types(id) on  
delete cascade,  
value varchar  
);

insert into user\_data\_types (name, code, restriction) values  
(‘Fullname’, ‘fullname’,null);  
insert into user\_data\_types (name, code, restriction) values (‘Zipcode’,  
‘zip’,’^[\d]{4}$’);

* * *

I have chosen this database-design to make the user data extendable.

I want to access userdata a hash-like way with the user:

user.id: \<%= @user.id %\>

user.fullname: \<%= @user.user\_data\_fields[:fullname] %\>

user.zip: \<%= @user.user\_data\_fields[:zip] %\>

So I decided to modify the User model:

class User \< ActiveRecord::Base  
has\_many :user\_data\_fields

```
    def after_find
            def user_data_fields.[](k)
                    if k.type != Symbol
                            super
                    else
                            self.each { |f| return f.value if

```

f.user\_data\_type.code.to\_sym == k }  
nil  
end  
end  
end  
end

* * *

Well, this works pretty well. It causes three selects, which can be  
reduced to two with using :include option of the find method.

However, since I am beginner, I would like to get some confirmation. Is  
the after\_find a right place to implement such a class extension? Is  
there an easier way that I missed?

Thank you for your time.

```
      Mage
```

---

<div class="post-metadata">

**Author:** ![Mage](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6f9a4e/32.png) [@Mage](https://www.ruby-forum.com/u/Mage)\
**Post date:** [August 20, 2006, 8:13pm UTC](https://www.ruby-forum.com/t/extending-activemodel-to-handle-multiple-tables-as-hash/65712/2 "2006-08-20T20:13:14Z")

</div>

Hello Mage,  
If I may jst take a couple of seconds of your life, and recount a  
(sadly) true story;

```
I started work about 7 years back, at a very large scale bank. I had

```

been brought in to try and diagnose why there was a slow down in the  
current system that they were using. It was a web-based order tracking  
system. The chief designer at the time had very little knowledge of  
database’s, nor what information was going to be stored in the system,  
nor infact, how the system would be used on a day to day basis. So. He  
did what your doing, or rather, he took it one step further.

```
He created a 'flex' table. This had three columns inside. The first

```

was ‘tablename’, the second was ‘column name’ and the third was ‘value’.  
This allowed him to add “columns” to the “table”, or even create whole  
new “tables” on an ‘ad-hoc’ basis. That was perhaps okay for the test  
sytem, and then after this, he could say ‘users should have firstname,  
and lastname’ etc. However, he left it and let it go into production.

```
So, when the amount of records hit 200k, and each 'record' had 17

```

‘fields’, well, that meant that -one- table had 17 rows, when it should  
have only had 1. Now, imagine storing around 40 tables inside this one  
‘flex’ table.

```
Mess.

Now, if we can relate this to your situation, your definitely going

```

down that road from what I can see, but, your also eschewing the whole  
‘validates\_’ helpers as well as getting rid of the ‘R’ in RDBMS. How do  
you expect to have any ‘relational’ query perform well agianst a “flex”  
table ?. That ‘restriction’ column also looks -suspiciously- like an  
attempt at a constraint, which, is re-inventing the wheel (and not  
‘well’, no offense meant). I would say either use the database  
constraints and/or the rails helpers.

```
This is, at least to my eyes, what you appear to be doing. If

```

nothing else, if not even for your own sanity, please think of any poor  
programmers who come after you. It’s true that programmers often think  
differently about the same problem, but, this is not the best way to go.

```
This is not an attack, nor a 'chewing out', but, perhaps a

```

suggestion to re-think how your using Rails. If this email offends you  
in anyway, feel free to ignore these as the mindless ramblings of a  
grizzled but optimistic programmer 🙂

```
Regards
Stef
```

---

<div class="post-metadata">

**Author:** ![Mage](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6f9a4e/32.png) [@Mage](https://www.ruby-forum.com/u/Mage)\
**Post date:** [August 20, 2006, 9:15pm UTC](https://www.ruby-forum.com/t/extending-activemodel-to-handle-multiple-tables-as-hash/65712/3 "2006-08-20T21:15:22Z")

</div>

Hello Stef,

this e-mail doesn’t offend me, moreover thank you for your time. I am  
glad to read it.

Like You I also have seen some messed databases, and even I know that  
coherent data should be put into one (but not two, three) table.

However, in the past I had to implement different login models every  
time when I started writing a new web-based application. My contractors  
wanted different things to be stored, to be logged in every systems we  
made.

I am trying to create a login system which is user-data independent.  
Which will be very same in every of my rails application. This is the  
reason of I put application-specific user-data and activity logs into  
separated tables.

I understand your point. Putting “Fullname” into another table is a very  
bad example. This field should be accessed at every page load, maybe  
because at the top of the page there will be a “Hello Mr./Mrs.  
#{fullname}” like text. However the chances are that zipcode, street,  
country data, postal address, phone number will not be read at most of  
page loads. User-data modification form will be used rarely. And if they  
are not accessed then they will not be read from the database.

Trivial data (fullname, email address) really must go into the “users”  
table.

You mentioned validators, which, in my opinion are a complicated part of  
Rails. Nothing but database rules, triggers and constraints can make the  
database consistent for sure. I cannot implement a system based only on  
Rails validators. I simply can’t. It would hurt me. I put every  
important constraints into the database too. Even because there might be  
cases when other clients are reading or writing the database, and they  
will not have the validators.

I was been thinking of this for a while, because it seems to break the  
DRY property of Rails, and then it turned out (for me) that is not a  
problem, even not the case. I think that validators are for telling the  
user in a human-readable, easy understable way that his/her entered data  
is wrong. Database constaints are for protecting the database’s  
consistence for 100%. I have to use both.

I think these field-specific constrains at the bottom of my email (zip  
=\> “^[\d]{4}$”) in the column “restriction” will only be used by the  
validators, because they are not related to consistence, only to  
business rules.

What’s your opinion after reading this? Did it change a bit?

```
   Mage
```

---

<div class="post-metadata">

**Author:** ![Mage](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6f9a4e/32.png) [@Mage](https://www.ruby-forum.com/u/Mage)\
**Post date:** [August 20, 2006, 10:01pm UTC](https://www.ruby-forum.com/t/extending-activemodel-to-handle-multiple-tables-as-hash/65712/4 "2006-08-20T22:01:29Z")

</div>

Hello Mage,  
Good good, jst making sure that I don’t cause offense. Sometimes,  
programmers tend to have … urm … ‘code love’ that verge’s on ‘code  
obsession’ (Eg; my way is -THE- right way ;). I don’t think there is  
anything ‘wrong’ or ‘bad’ about thinking about a problem differently,  
and good to know that you don’t either 🙂

```
I heartily agree with you that you should really use validators

```

-AND- constraints, or rather, use logic at the user level as -well- as  
putting the checks in the database as well. I can understand that you  
may want other clients accessing your database, so you want to stop them  
from putting in a non-zip into a zip field. I can even understand the  
intent of DRY’ing the code into the database and then grabbing it out to  
use as a constraint inside RoR, although, this does then seem to be  
R’ing in the DRY. It’s also redundant in my eyes, because there is  
nothing to say that other clients will even honor the restraints at the  
user level, so storing them appears - well - redundant. However, thats  
your personal call, your closer to the application than me 😉

```
I guess my other question/query is, -why- are you wanting to

```

re-implement an authentication system ? _chuckles_ _raises hands_ now  
now, not that I am saying its a bad idea if you want to learn and play  
with RoR. Heck, I make test systems that do all sorts of ‘funky’ things  
and then promptly fling them away. If its not, however, may I suggest  
one of the pre-rolled gems ?

```
script/plugin discover
script/plugin install acts_as_authenticated
script/generate authenticated User Account
before_filter :login_required

In your controller and you have it protected by using the gem

```

acts\_as\_authenticated. I think it has quite a bit of other goodness  
inside it as well. Path of Least Work - in a real project - would be the  
way I would go 😉 There is also user\_engine of course. Ymmv 😉

```
Then again, if your doing this as a -learning- exercise, more power

```

to you. Personally, I would have a table of ‘logins’ which keeps track  
of whom authenticated (or tried to). A login page would actually query  
directly against the user table (using username, password and ‘isActive’  
or such). on success (or failure 😉 fling a ‘login attempt/success’ into  
the login table and it should all be good. Then again, if your doing  
this to learn, then whichever way you want to do it is ‘the right way’.  
The ‘wrong way’, when your learning, will become apparent, as you will  
have to start adding layer and layer of complexity into the system.  
Remember, in Ruby (to horribly mangle Keats) ‘simple is beauty, and  
beauty is simple’\*

```
Regards, good luck, and let us all know what you decide to do :)
Stef

```

(\* The original quotation is, of course, 'Beauty is truth, truth beauty

- that is all, Ye know on earth, and all ye need to know’)

---

<div class="post-metadata">

**Author:** ![Mage](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6f9a4e/32.png) [@Mage](https://www.ruby-forum.com/u/Mage)\
**Post date:** [August 20, 2006, 10:45pm UTC](https://www.ruby-forum.com/t/extending-activemodel-to-handle-multiple-tables-as-hash/65712/5 "2006-08-20T22:45:34Z")

</div>

Hello Stef T,

of course I like my code, but if you say things which extend my mind  
then I will write better code. And I will love the better code more.

The reason of putting regular expression contrains into database is that  
these fields are dynamically extendable.

With using a static user table, these restrictions would go to the  
model, but if I define the new user-attributes in a table, shouldn’t I  
put the adequat rules nearby? And if one day I happen to implement these  
format-restrictions in database level, I will only have to write a  
stored procedure in plperl or plpython or, what I really wish, that day  
postgresql will support plruby (officially).

(Well, I am not sure. I am just thinking…)

You guessed well, I implement the login system for learning Rails, which  
seems to be a good lesson to challenge my fresh knowledge about models,  
sessions, cookies, controllers, partial templates and maybe even AJAX. I  
keep the book open although.

On the second hand, there are many types of authentication. I will write  
a scalable one, allowing one user to be logged from multiple computers  
at same time, optionally keeping each of his login alive on the  
computers he/she use (‘remember me’ function). He must be able to log  
out from every logged computer at once if he wants. I also will  
implement toggleable logging of ip addresses browser types.

Maybe there is a ready-to-use generator for all of these, but what I  
mostly like in Ruby and Rails that coding is very fast. I will be  
finished in one day or two, then, as you have written, I can fine tune  
my code.

And I am curious to know the answer for my first question, in general.  
Is the after\_find callback a good place to extend a model’s children  
array? I was a bit surprised when realized that has\_many relationship  
makes the children a simple array of similar activemodels. I was  
expected one, array-like object.

```
   Mage
```

---

<div class="post-metadata">

**Author:** ![Mage](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/6f9a4e/32.png) [@Mage](https://www.ruby-forum.com/u/Mage)\
**Post date:** [August 21, 2006, 12:31am UTC](https://www.ruby-forum.com/t/extending-activemodel-to-handle-multiple-tables-as-hash/65712/6 "2006-08-21T00:31:44Z")

</div>

Hello Mage,

Mage wrote:

> format-restrictions in database level, I will only have to write a  
> stored procedure in plperl or plpython or, what I really wish, that day  
> postgresql will support plruby (officially).
> 
> (Well, I am not sure. I am just thinking…)

Oh no, perfectly okay, although thinking tends to get me into trouble 😉  
You know, if you look for dr nic and his magic modules, there is even a  
way to have constraints such as maxlength etc enforced without you  
having to use validates… may not help in the case of the zip but… you  
get the idea 🙂 Food for thought, either way 🙂

> You guessed well, I implement the login system for learning Rails, which  
> seems to be a good lesson to challenge my fresh knowledge about models,  
> sessions, cookies, controllers, partial templates and maybe even AJAX. I  
> keep the book open although.

If its all for ‘learning’, then thats perfectly understandable. Be  
advised though, that acts\_as\_authenticate also has (on its homepage I  
believe) snippets of code. One of which does the ‘remember me’ function  
you describe 😉

> Maybe there is a ready-to-use generator for all of these, but what I  
> mostly like in Ruby and Rails that coding is very fast. I will be  
> finished in one day or two, then, as you have written, I can fine tune  
> my code.

Ah. once on the lips, lifetime on the hips. (or to re-phrase, easy to  
code, harder to debug :). But, again, your code and your learning route  
😃

> And I am curious to know the answer for my first question, in general.  
> Is the after\_find callback a good place to extend a model’s children  
> array? I was a bit surprised when realized that has\_many relationship  
> makes the children a simple array of similar activemodels. I was  
> expected one, array-like object.

To be honest, in ‘general’ in Rails, I don’t think that most people -do-  
extend the children’s array after a find [watch someone now quote that  
in application X they do Y because of Z ;]. So. if it works for you, it  
works _polite shrug_ Your trying to work around Rails other functions,  
so why worry about this one 😜 (joking, sort of, but not meaning it in a  
derogatory way, I assure you 🙂

Regards and happy hacking  
Stef
