I''m wondering what the most Rails-ish way to achieve the following is: I have some records in a database table (tariffs for a car park), and it''s possible to add as many different tariff rates as needed to cover Christmas, public holidays, special offers and so on. However, there''s an initial six tariffs (low season and high season 1-5) that should be possible to update the rates on, but not delete or rename since they must always remain available. I''m considering adding a "no_delete" column in the database, and making my Rails destroy function only delete where no_delete = 0, and setting the undeleteable items to have no_delete = 1. Not so sure what to do for not allowing the names to be changed? Maybe just refuse to update the name in these particular cases, by checking them before updating. Just wondering if there''s a better way to do this? I''m using Postgresql, so if necessary could make use of a stored procedure or similar to prevent them being deleted or renamed. I can think of ways I would have done this in PHP, but am attempting to clean up my coding since moving to a platform that allows me to write nicer code. So, if there''s a non-kludgy way to accomplish this, please let me know! :-) Any and all suggestions welcome, and thanks very much for your help! Cheers, ~Dave -- Dave Silvester Rent-A-Monkey Website Development Web: http://www.rentamonkey.com/
On 8/25/05, Dave Silvester <dave-AJqNGCqIqVQ7cdpDWioORw@public.gmane.org> wrote:> I''m wondering what the most Rails-ish way to achieve the following is: > > I have some records in a database table (tariffs for a car park), and it''s > possible to add as many different tariff rates as needed to cover Christmas, > public holidays, special offers and so on. However, there''s an initial six > tariffs (low season and high season 1-5) that should be possible to update the > rates on, but not delete or rename since they must always remain available. > > I''m considering adding a "no_delete" column in the database, and making my > Rails destroy function only delete where no_delete = 0, and setting the > undeleteable items to have no_delete = 1. Not so sure what to do for not > allowing the names to be changed? Maybe just refuse to update the name in > these particular cases, by checking them before updating. > > Just wondering if there''s a better way to do this? I''m using Postgresql, so > if necessary could make use of a stored procedure or similar to prevent them > being deleted or renamed. > > I can think of ways I would have done this in PHP, but am attempting to clean > up my coding since moving to a platform that allows me to write nicer code. > So, if there''s a non-kludgy way to accomplish this, please let me know! :-) > > Any and all suggestions welcome, and thanks very much for your help! > > Cheers, > > ~DaveCheck out my post on paranoid active record models: http://techno-weenie.net/blog/code/251/paranoid-activerecord-models Someday I may get the inclination to move this into an act (acts_as_paranoid?). I was able to add this to an existing project with no issues so far. Oh, I suppose it could use a revive method too, that sets deleted_at = null. Note: this requires a recent beta version of rails that supports the #constrain method. If the latest beta gems don''t support it, you''ll have to run on edge rails until the next official release. -- rick http://techno-weenie.net
On 8/25/05, Dave Silvester <dave-AJqNGCqIqVQ7cdpDWioORw@public.gmane.org> wrote:> I''m wondering what the most Rails-ish way to achieve the following is: > > I have some records in a database table (tariffs for a car park), and it''s > possible to add as many different tariff rates as needed to cover Christmas, > public holidays, special offers and so on. However, there''s an initial six > tariffs (low season and high season 1-5) that should be possible to update the > rates on, but not delete or rename since they must always remain available. > > I''m considering adding a "no_delete" column in the database, and making my > Rails destroy function only delete where no_delete = 0, and setting the > undeleteable items to have no_delete = 1. Not so sure what to do for not > allowing the names to be changed? Maybe just refuse to update the name in > these particular cases, by checking them before updating. > > Just wondering if there''s a better way to do this? I''m using Postgresql, so > if necessary could make use of a stored procedure or similar to prevent them > being deleted or renamed.You could define a postgresql rule to override update/delete statements. You could also add another table such as restricted_tarrifs with foreign keys on the appropriate columns in the table that holds your tarrifs. Postgresql gives you quite a few options for enforcing this type of thing at the database layer. Chris
Rick Olson wrote:> Check out my post on paranoid active record models: > http://techno-weenie.net/blog/code/251/paranoid-activerecord-modelsThanks for that Rick, although I''m not sure it''s quite what I need. See, these records should not be deletable, or even marked as deletable - they''re almost like semi-constants in a way, in that they must always be present, but that their value may be updated from time to time. Perhaps I could define the names of the undeletable records in an actual constant in my application, and then just prevent them being deleted or renamed using some checks? It still feels rather kludgy though! :-S Cheers, ~Dave -- Dave Silvester Music Technology Junkie | Rentable Website Monkey http://www.mu-sly.co.uk | http://www.rentamonkey.com
on 8/25/2005 9:29 AM Dave Silvester said the following:> I''m wondering what the most Rails-ish way to achieve the following is:> I have some records in a database table (tariffs for a car park), and > it''s possible to add as many different tariff rates as needed to cover > Christmas, public holidays, special offers and so on. However, > there''s an initial six tariffs (low season and high season 1-5) that > should be possible to update the rates on, but not delete or rename > since they must always remain available. > > I''m considering adding a "no_delete" column in the database, and > making my Rails destroy function only delete where no_delete = 0, and > setting the undeleteable items to have no_delete = 1. Not so sure > what to do for not allowing the names to be changed? Maybe just > refuse to update the name in these particular cases, by checking them > before updating. > > Just wondering if there''s a better way to do this? I''m using > Postgresql, so if necessary could make use of a stored procedure or > similar to prevent them being deleted or renamed.What I would do is create a second small administrator application for administering the rates. This application would have a different database user and password, and that user would have full access to the tariff rates table. The database user for the rest of the application would have read only access to the rates table. Advantages to this scheme: 1) Clarity. Read only data is read only, no need to clutter your application with corner cases. You never allow normal users to change the rates. Full stop. 2) The logic for changing the rates can be encapsulated. You could even try "the simplest thing that could possibly work" which would be some instructions on the administrator page not to change the names of the first six rates. If that is insufficient, then you can still enforce more logic with additional columns or whatever your business rules are, but this is shielded from that average user. 3) Changing the rates is likely to be something that only selected users can do. By having this segregated into a separate application, you enforce this. Even if all users are allowed to change the rates, pushing them to a separate app to do it, draws a mental line in the sand. 4) This administrator interface will likely prove useful for a number of other tasks, and it will give you a good deal of flexibility in the future. You can deploy your base app to multiple servers, and still keep the admin app on a single server. 5) This approach tends to be an easy sell to users, clients and customers. If you are saying, "I have logic in the application that ensures that the rate changes will never be made incorrectly," it is much less reassuring than saying, "Rates can only be changed by authorized users through the administrative interface." Disadvantages: 1) In some ways this scheme is more complicated. You have two applications and two database users where you only had one of each before. This means two sets of logs, two database passwords, two configurations and perhaps two urls. This doesn''t double your maintenance work, but it does increase it, especially for setup and when you first deploy. 2) Some people are confused by database permissions. That includes developers, DBA, sys admins and users. If you are doing all of those yourself, there is only one level of confusion, but if you need to communicate to others, this can add some time. 3) Unknown: I haven''t investigated using multiple users on Postgres, so the ease of setting per table privileges is unknown to me. One thing that I would want to know is if it will ever be necessary to know the rate for a particular tariff at some time in the past. Will you need to generate reports for the rate for the past year, or the income at each rate over the same period? Ray
Dave, Perhaps those six "standard" records should never be entered in the database at all. Rather, define them and hold them as a set of constant ruby objects. Have the database just hold the "nonstandard" data. I think your described situation is common and I too have been wondering if there''s a nice Rails solution to combining static constant data and database data. Brian
Will these values need to be edited by non-programmers? Will they need to be used (and normalized) across several applications? The way this would be handled if you weren''t using Rails is likely that you''d restrict access at the RDBMS level and have your application switch DB accounts when an authorized user (an admin, or whatever) needs to mod these records. There is no nice way to use multiple database accounts with Rails, as far as I know, but someone posted a method of switching DB connections per model class. It isn''t the same, and isn''t nearly fine- grained enough for most uses, but for your use (table-level restrictions) it should be workable. On Aug 26, 2005, at 10:19 PM, Brian Buckley wrote:> Dave, > > Perhaps those six "standard" records should never be entered in the > database at all. Rather, define them and hold them as a set of > constant ruby objects. Have the database just hold the "nonstandard" > data. > > I think your described situation is common and I too have been > wondering if there''s a nice Rails solution to combining static > constant data and database data. > > Brian > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Toby Boudreaux wrote:> Will these values need to be edited by non-programmers?Yes. They will only be alterable by management level admins though, but essentially, yes, they do need to be alterable (although not particularly often). Still, management should not be able to delete or rename these items - only alter the price. I think I now have a way of enforcing that (foreign key constraints from another table to actually prevent deletion), as well as a way to not offer deletion from within rails by comparing these items to a constant that lists the ones that can''t be deleted or renamed. Not exactly DRY, but about as good as it''s going to get, I guess. There are two other levels of site access: staff (who can make booking sand change some smaller things, but don''t have superuser rights to change things like tariffs) and public (who can only create and update bookings).> Will they need to be used (and normalized) across several applications?No, just this one, although when finished it will have several sub-applications going on in the form of a public front end, a staff front end and a management back end, as well as some other stuff that enables other systems to talk to the database (although not in this initial phase).> The way this would be handled if you weren''t using Rails is likely that > you''d restrict access at the RDBMS level and have your application > switch DB accounts when an authorized user (an admin, or whatever) > needs to mod these records.That would be good, but...> There is no nice way to use multiple database accounts with Rails, as > far as I know, but someone posted a method of switching DB connections > per model class. It isn''t the same, and isn''t nearly fine- grained > enough for most uses, but for your use (table-level restrictions) it > should be workable.I will certainly look into this. It does seem to be a slight oversight that AFAIK there''s no default way to use different database accounts, since one of the basic tenets of good database security is to always use the lowest privileges that will get the job done, and lock people out of stuff they don''t need to access, especially when it comes to write access. For example, in my system, the public making bookings would ideally not use the same database account as the site admins, since there is no need to give them write access to the tables controlling price and so on (although they need to be able to read from them). But again, the public don''t need read/write access to the table of staff accounts, so it would be much safer if I could lock them out completely at database level. I''ll see what I can find about this switching DB connection per class, since that should probably do the trick, but long term, perhaps there''s a neater way this could be done in Rails (as a convention, naturally)? Is anyone working on something like that already, since I imagine a lot of people would want to make use of it to help make their applications more security-hardened? Cheers, ~Dave -- Dave Silvester Rent-A-Monkey Website Development Web: http://www.rentamonkey.com/
Dave Silvester wrote:> Toby Boudreaux wrote: > >> Will these values need to be edited by non-programmers? > > > Yes. They will only be alterable by management level admins though,...> There are two other levels of site access: staff (who can make booking > sand change some smaller things, but don''t have superuser rights to > change things like tariffs) and public (who can only create and update > bookings).Probably rbac (role base access) will be your solution. Have a look on https://rbaconrails.turingstudio.com/trac/wiki/HowToRunTheDemo -- Jean-Christophe Michel