Question

I am using Ruby on Rails v3.2.2 and I would like to "protect" a class/instance attribute so that a database table column value can be updated only one way. That is, for example, given I have two database tables:

table1
- full_name_column

table2
- name_column
- surname_column

and I manage the table1 so that the full_name_column is updated by using a callback stated in the related table2 class/model, I would like to make sure that it is possible to update the full_name_column value only through that callback.

In other words, I should ensure that the table2.full_name_column value is always

"#{table1.name_column} #{table1.surname_column}"

and that it can't be another value. So, for example, if I try to "directly" update the table1.full_name_column, it should raise something like an error. Of course, that value must be readable.

Is it possible? What do you advice on handling this situation?


Reasons to this approach...

I want to use that approach because I am planning to perform database searches on table1 columns where the table1 contains other values related to a "profile"/"person" object... otherwise, probably, I must make some hack (maybe a complex hack) to direct those searches to the table2 so to look for "#{table1.name_column} #{table1.surname_column}" strings.

So, I think that a simple way is to denormalize data as explained above, but it requires to implement an "uncommon" way to handling that data.

BTW: An answer should be intend to "solve" related processes or to find a better approach to handle search functionalities in a better way.

Was it helpful?

Solution

By replicating the data from table2 into table1 you've already de-normalized it. As with any de-normalization, you must be disciplined about maintaining sync. This means not updating things you're not supposed to.

Although you can wall off things with attr_accessible to prevent accidental assignment, the way Ruby works means there's no way to guarantee that value will never be modified. If someone's determined enough, they will find a way. This is where the discipline comes in.

The best approach is to document that the column should not be modified directly, block mass-assignment with attr_accessible, and leave it at that. There's no concept of a write-protected attribute, really, as far as I know.

OTHER TIPS

Here's two approaches for maintaining the data on database level...

Views and materialized tables.

If possible, the table1 could be VIEW or for example MATERIALIZED QUERY TABLE (MQT). The terminology might differ slightly, depending on the used RDMS, I think Oracle has MATERIALIZED VIEWs whereas DB2 has MATERIALIZED QUERY TABLEs.

VIEW is simply an access to data that is physically in some different table. Where as MATERIALIZED VIEW/QUERY TABLE is a physical copy of the data, and therefore for example not in sync with source data in real time.

Anyway. these approaches would provide read-only access to data, that is owned by table2, but accessible by table1.

Example of very simple view:

CREATE VIEW table1 AS 
   SELECT surname||', '||name AS full_name
     FROM table2;

Triggers

Sometimes views are not convenient as you might actually want to have some data in table1 that is not available from anywhere else. In these cases you could consider to use database triggers. I.e. create trigger that when table2 is updated, also table1 is updated within the same database transaction.

With the triggers the problem might be that then you have to give privileges to the client to update table1 also. Some RDMS might provide some ways to tune access control of the triggers, i.e. the operations performed by TRIGGERs would be performed with different privileges from the operations that initiate the TRIGGER.

In this case the TRIGGER could look something like this:

   CREATE TRIGGER UPDATE_NAME
     AFTER UPDATE OF NAME, SURNAME ON TABLE2
     REFERENCING NEW AS NEWNAME
     FOR EACH ROW
     BEGIN ATOMIC
       UPDATE TABLE1 SET FULL_NAME = NEWNAME.SURNAME||', '||NEWNAME.NAME
        WHERE SOME_KEY = NEWNAME.SOME_KEY
     END;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top