Manuel Holtgrewe
2005-Sep-16 18:59 UTC
ActiveRecord Flaw Makes It Impossible To Do Previews?
Hi all. I''ve just gone two days from startlement to lack of comprehension that it seems not to be possible to implement previews with Ruby On Rails without letting down the elegance my code usually has with Rails. In my opinion there is a very major flaw in ActiveRecord that makes previews close to impossible: About every time you change something in Ruby, you automatically change the database. Mow. While this is no problem as long as I really want this, it really makes no sense for many application that require a "Preview" button. Of course, you can set attributes using model.attributes= or set them bit by bit. However, the "favourite" method - "update_attributes" automatically changes the database state. Additionally, when updating relations, these changes are *always* persisted immediately - but for when you change relations on a yet unsaved object. Okay, I thought, just go ahead, create an unsaved clone of your model object, change whatever you want there and push that to the preview. Then, simply call model.valid? to force validation without saving. However, this does not work, of course, if you have an "validate_uniqueness_of" constraint on one of your model''s fields. I want to have a form to edit articles with a "preview" and a "update" button where the preview button only displays the form again and then a preview of my article. My article model has a n:m relation to the author model. Article titles are unique. So I seem to be stuck with the following options: * Set the non-relation attributes of the primary class and call model.valid? to validate the simple attributes. Then create a clone, change its attributes and set it into the template for preview. This works for my case but when you want to validate attributes too you have to create a clone with fake attributes so you don''t break the unique constraints. Well, this is very hacky! * Set the attributes of the model manually, then call validate on them. Put the relation attributes to the template into differen variables. This is not very elegant. Why can''t I simply do something like the following? @article.find params[:id] @article.title = params[:article][:title] ... params[:article][:authors].each do |author_id| @article.authors << Author.find author_id end Is there something obvious I am missing? Has anyone implemented a preview feature? Or is it just that nobody does previews? No Rails based open source application supports previews the way I described above. Even Basecamp has no previews. I would really appreciate any hint into the right direction. Regards Manuel Holtgrewe
Doug Alcorn
2005-Sep-16 19:21 UTC
Re: ActiveRecord Flaw Makes It Impossible To Do Previews?
Manuel Holtgrewe <purestorm-nlpEiS6K5uusTnJN9+BGXg@public.gmane.org> writes:> Of course, you can set attributes using model.attributes= or set them > bit by bit. However, the "favourite" method - "update_attributes" > automatically changes the database state.Yes, I''ve been frustrated by this before too.> Is there something obvious I am missing? Has anyone implemented a > preview feature? Or is it just that nobody does previews? No Rails > based open source application supports previews the way I described > above. Even Basecamp has no previews.I''ve been playing with acts_as_versioned this morning. Not too tricky to setup. It took me two hours, but most of that was me just being stupid and getting distracted. What this would let you to is go ahead and save your object with update_attributes, and then revert_to the previous version if they cancel after preview. http://wiki.rubyonrails.com/rails/show/ActsAsVersioned -- Doug Alcorn - http://lathi.net/RubyOnRailsDeveloper doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org
Jay Levitt
2005-Sep-16 19:44 UTC
Re: ActiveRecord Flaw Makes It Impossible To Do Previews?
In article <m2ek7o3jkj.fsf-HEBgovpM+ff0Kn81hEinErNAH6kLmebB@public.gmane.org>, doug- jGAhs73c5XxeoWH0uzbU5w-XMD5yJDbdMReXY1tMh2IBg@public.gmane.org says...> It took me two hours, but most of that was me just being > stupid and getting distracted.Doug: If you find a workaround for that, please let me know - I''ve been having the same problems with Rails. -- Jay Levitt | Wellesley, MA | I feel calm. I feel ready. I can only Faster: jay at jay dot fm | conclude that''s because I don''t have a http://www.jay.fm | full grasp of the situation. - Mark Adler
Manuel Holtgrewe
2005-Sep-16 19:47 UTC
Re: ActiveRecord Flaw Makes It Impossible To Do Previews?
Am 16.09.2005 um 21:21 schrieb Doug Alcorn:> I''ve been playing with acts_as_versioned this morning. Not too tricky > to setup. It took me two hours, but most of that was me just being > stupid and getting distracted. > > What this would let you to is go ahead and save your object with > update_attributes, and then revert_to the previous version if they > cancel after preview.Well, when they simply close their browser window you are stuck with the changes - or am I mistaken there? One thing I could imagine is starting a session, change the object and then cancel the transaction by throwing an Exception (gah!). Another possibility would be doing a "deep clone" using marshall/ unmarshall and then undoing things manually instead of throwing the Exception. This offers possible solutions to the problems. However, these solutions are neither beautiful nor elegant nor will they offer good performance. I guess if I do not find a good way to do this, I will override "validates_uniqueness_of" of ActiveRecord so even if the record has not been saved yet, it ignores duplicates with the same id. The "validates_uniqueness_of" method currently checks for the record to be changed being saved yet. If it is not, it excludes the record from its "SELECT * FROM record WHERE property = #{value}" query with "AND id <> #{current_id}". If anyone has a more elegant and consistent way of implementing previews, I''d desperately like to read it! Regards Manuel Holtgrewe
Doug Alcorn
2005-Sep-16 20:03 UTC
Re: ActiveRecord Flaw Makes It Impossible To Do Previews?
Manuel Holtgrewe <purestorm-nlpEiS6K5uusTnJN9+BGXg@public.gmane.org> writes:> One thing I could imagine is starting a session, change the object > and then cancel the transaction by throwing an Exception (gah!). > Another possibility would be doing a "deep clone" using marshall/ > unmarshall and then undoing things manually instead of throwing the > Exception.It wouldn''t be that hard to re-implement update_attributes so that it doesn''t save. def update_attributes_no_save(hash) hash.keys.each do |key| if self.responds_to?("#{key}=") self.send("#{key}=", hash[:key]) end end end I think that''s basically what update_attributes does and then does a self.save. -- Doug Alcorn - http://lathi.net/RubyOnRailsDeveloper doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org
Rick Bradley
2005-Sep-16 20:37 UTC
Re: ActiveRecord Flaw Makes It Impossible To Do Previews?
* Doug Alcorn (doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org) [050916 15:10]:> It wouldn''t be that hard to re-implement update_attributes so that it > doesn''t save. > > def update_attributes_no_save(hash) > hash.keys.each do |key| > if self.responds_to?("#{key}=") > self.send("#{key}=", hash[:key]) > end > end > end > > I think that''s basically what update_attributes does and then does a > self.save.Seems like the simplest refactoring then would be to take the non-save part of update_attributes(), extract it as something like update_attributes_no_save, and then change update_attributes() to be: def update_attributes(hash) update_attributes_no_save(hash) self.save() end Rick -- http://www.rickbradley.com MUPRN: 523 | I am searching random email haiku | and then go away and read | them somewhere else.
Rick Olson
2005-Sep-16 20:55 UTC
Re: ActiveRecord Flaw Makes It Impossible To Do Previews?
> Seems like the simplest refactoring then would be to take the non-save > part of update_attributes(), extract it as something like > update_attributes_no_save, and then change update_attributes() to be: > > def update_attributes(hash) > update_attributes_no_save(hash) > self.save() > endLook at the actual source of update_attributes: def update_attributes(attributes) self.attributes = attributes save end That should tell you what you need :) Doug: I added a tip about creating the versioned table to that wiki page. I''ll work on some decent docs this weekend for the thing. Hope it works out for you.. -- rick http://techno-weenie.net
Rick Olson <technoweenie-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:> Doug: I added a tip about creating the versioned table to that wiki > page. I''ll work on some decent docs this weekend for the thing. > Hope it works out for you..I saw that create_versioned_table method, but wasn''t sure how to use it. Your migration example is perfect, thanks! -- Doug Alcorn - http://lathi.net/RubyOnRailsDeveloper doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org
Manuel Holtgrewe
2005-Sep-16 23:02 UTC
Re: ActiveRecord Flaw Makes It Impossible To Do Previews?
Am 16.09.2005 um 22:55 schrieb Rick Olson:> Look at the actual source of update_attributes: > > def update_attributes(attributes) > self.attributes = attributes > save > end > > That should tell you what you need :)Yes, as I wrote:>>> Of course, you can set attributes using model.attributes= or set >>> them bit by bit. However, the "favourite" method - >>> "update_attributes" automatically changes the database state.But this does not help with relations. Relations are stored to the database immediately. They are not stored to the database for records not already in the database. When I create a new record not in the database, assign attributes to it and call model.valid?, I get errors because the uniqueness validator method rightfully detects that I have a new record that has the same title as an already existing record. It would be no workaround to remove uniqueness validation depending on a "is_preview" flag since I need uniqueness validation - but it should ignore just one other record in the database: The that has the same id as the current model object. Do you have any idea of how to implement setting relations without saving with ActiveRecord? Model.collection.build() is not a solution since it is "add only" and seems only to work for new objects. Regards Manuel Holtgrewe
Doug Alcorn
2005-Sep-17 03:55 UTC
Re: Re: ActiveRecord Flaw Makes It Impossible To Do Previews?
Jay Levitt <jay-news-WxwZQdyI2t0@public.gmane.org> writes:> In article <m2ek7o3jkj.fsf-HEBgovpM+ff0Kn81hEinErNAH6kLmebB@public.gmane.org>, doug- > jGAhs73c5XxeoWH0uzbU5w-XMD5yJDbdMReXY1tMh2IBg@public.gmane.org says... >> It took me two hours, but most of that was me just being >> stupid and getting distracted. > > Doug: > > If you find a workaround for that, please let me know - I''ve been having > the same problems with Rails.Ha! The best antidote for both those problems is pair programming. -- Doug Alcorn - http://lathi.net/RubyOnRailsDeveloper doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org