Hi, When I have a transaction block like this: ActiveRecord::Base.Transaction do cars.each do | car | car.dosomething car.save! end end When the last car in the collection fails, all the others will have gotten an ID. That means that if the fault results in a validation error, and I correct the form and resubmit, rails say it can''t find a car with that id. It''s not very atomic this way. I can solve it partly by setting the id''s to nil in a rescue clause, but that has a drawback. In my form, I want certain fields to be disabled when editing an existing record (as opposed to creating a new one). I use car.new_record? for that. But, when the validation fails and I submit, and submit again, because of the loss of ID, rails doesn''t know anymore that it was an existing record, and new_record? will return true. So, my question: is there a way to unset the id and still let rails think the record already exists in the DB? Is it dangerous to make a method in AR::Base, which sets @new_record to true and id to nil? Or, even better, is it possible to have true atomic transactions in rails models? (probably not, because there is no uncomitted state of variables in ruby, but I thought I''d ask...) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
> -----Original Message----- > From: rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org > [mailto:rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org] On Behalf Of halfgaar > Sent: Tuesday, June 26, 2007 3:47 PM > To: Ruby on Rails: Talk > Subject: [Rails] Atomic transactions in rails controllers > > > Hi, > > When I have a transaction block like this: > > ActiveRecord::Base.Transaction do > cars.each do | car | > car.dosomething > car.save! > end > end >Rails seems to fall down a bit when you want to edit multiple child records on one form. I''ve solved this problem by tying each child record to it''s parent, and then I save! the parent, which also seems to validate and save it''s children if necessary. I assign ID numbers before I create the records so that I can manipulate the correct div via ajax calls. Each child is in a div like <div id="email_1234567">, so without an id, the div doesn''t work right. Because the child records are tied to the parent, the parent is saved first, and then it''s ID is applied via the has_many relationship to the children records. So, the unique number that I temporarily assign for handling the div is correctly replaced by rails. Rails seems smart enough to run the validations before attempting to save, so no records wind up in the database until they all test as valid. def signup unless request.post? # initialize the view, set temporary id numbers @user = User.new @user.emails << Email.new do |o| o.id = Time.now.to_i o.emailtype_id = 1 # business end @user.phones << Phone.new do |o| o.id = Time.now.to_i o.phonetype_id = 1 # business end @user.addresses << Address.new do |o| o.id = Time.now.to_i o.addresstype_id = 1 # business end else # post, so assign fields to objects @user = User.new(params[:user]) # the model protects the user name, password and admin flag from mass assignment # so set them here @user.login = params[:user][:login] @user.password = params[:user][:password] # attach sub-models to model params[:email].each {|e| @user.emails << Email.new(e)} if params[:email] params[:phone].each {|t| @user.phones << Phone.new(t)} if params[:phone] params[:address].each {|a| @user.addresses << Address.new(a)} if params[:address] # validate and save the whole shebang @user.save! redirect_back_or_default(:controller => ''/account'', :action => ''thankyou'') flash[:notice] = "Thanks for signing up!" end rescue ActiveRecord::RecordInvalid # hack, assign id numbers to the sub-models so that the view will render correctly # things will get very weird if the id''s in the user table approach that of the current # time in seconds. It''s quite unlikely, however. count = 0 [@user.emails, @user.addresses, @user.phones].flatten!.each do |obj| obj.id = Time.now.to_i + count unless obj.id count = count + 100 # try to make sure we won''t get the same id for multiple objects end end In order for this to work, the fields for, example, the phone partial need to look something like: <% @phone = phone %> <div id="<%= "phone_#{phone.id}" %>"> <%= hidden_field_tag ''phone[][id]'', phone.id %> <label>Telephone Number:<br/> <%= text_field_tag ''phone[][number]'', phone.number, :size => 15 %><br/> <%= error_message_on ''phone'', ''number'', ''Telephone Number '', '''', ''errorMessage'' %> </div> HTH Regards, Rich --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Jun 26, 2007, at 11:41 PM, Duzenbury, Rich wrote:> Rails seems to fall down a bit when you want to edit multiple child > records on one form. I''ve solved this problem by tying each child > record to it''s parent, and then I save! the parent, which also > seems to > validate and save it''s children if necessary.If validates_associated. -- fxn --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Jun 27, 10:16 am, Xavier Noria <f...-xlncskNFVEJBDgjK7y7TUQ@public.gmane.org> wrote:> If validates_associated.Hey, now this may be very convenient. I was about to reply to Rich that in my controllers, rails was very unpredictable when it comes to validating has_many collections (it sometimes would and sometimes wouldn''t), and I have some very klunky code to work around that, but this may just solve all of that. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Jun 26, 11:41 pm, "Duzenbury, Rich" <R...-qLTRsCMXNVoAvxtiuMwx3w@public.gmane.org> wrote:> Rails seems to fall down a bit when you want to edit multiple child > records on one form. I''ve solved this problem by tying each child > record to it''s parent, and then I save! the parent, which also seems to > validate and save it''s children if necessary. I assign ID numbers before > I create the records so that I can manipulate the correct div via ajax > calls. Each child is in a div like <div id="email_1234567">, so without > an id, the div doesn''t work right. > > Because the child records are tied to the parent, the parent is saved > first, and then it''s ID is applied via the has_many relationship to the > children records. So, the unique number that I temporarily assign for > handling the div is correctly replaced by rails. Rails seems smart > enough to run the validations before attempting to save, so no records > wind up in the database until they all test as valid. > > def signup > unless request.post? > # initialize the view, set temporary id numbers > @user = User.new > @user.emails << Email.new do |o| > o.id = Time.now.to_i > o.emailtype_id = 1 # business > end > @user.phones << Phone.new do |o| > o.id = Time.now.to_i > o.phonetype_id = 1 # business > end > @user.addresses << Address.new do |o| > o.id = Time.now.to_i > o.addresstype_id = 1 # business > end > else > # post, so assign fields to objects > @user = User.new(params[:user]) > > # the model protects the user name, password and admin flag from > mass assignment > # so set them here > @user.login = params[:user][:login] > @user.password = params[:user][:password] > > # attach sub-models to model > params[:email].each {|e| @user.emails << Email.new(e)} if > params[:email] > params[:phone].each {|t| @user.phones << Phone.new(t)} if > params[:phone] > params[:address].each {|a| @user.addresses << Address.new(a)} if > params[:address] > > # validate and save the whole shebang > @user.save! > redirect_back_or_default(:controller => ''/account'', :action => > ''thankyou'') > flash[:notice] = "Thanks for signing up!" > end > rescue ActiveRecord::RecordInvalid > # hack, assign id numbers to the sub-models so that the view will > render correctly > # things will get very weird if the id''s in the user table > approach that of the current > # time in seconds. It''s quite unlikely, however. > count = 0 > [@user.emails, @user.addresses, @user.phones].flatten!.each do > |obj| > obj.id = Time.now.to_i + count unless obj.id > count = count + 100 # try to make sure we won''t get the same id > for multiple objects > end > end > > In order for this to work, the fields for, example, the phone partial > need to look something like: > > <% @phone = phone %> > <div id="<%= "phone_#{phone.id}" %>"> > <%= hidden_field_tag ''phone[][id]'', phone.id %> > <label>Telephone Number:<br/> > <%= text_field_tag ''phone[][number]'', phone.number, :size => 15 > %><br/> > <%= error_message_on ''phone'', ''number'', ''Telephone Number '', '''', > ''errorMessage'' %> > </div> > > HTH > > Regards, > RichFirst, see my reply to Xavier''s message. While it doesn''t solve my new_record issue, you did help me with another issue, but I do have a question. When you assign ID''s to new objects, doesn''t it complain about trying to save records which don''t exists, because the ID''s are not present in the DB? Or, does it only do that when new_record? == false? BTW, I always solved the id of the div issue by assigning id''s based on Time.now.to_s when the partial in question was rendered for an object that didn''t exist in the DB yet. I will be exploring your method, since it looks cleaner. Another thing: why aren''t you using text_field(model, method) as opposed to using text_field_tag, and then implementing what text_field already does for you, including marking it red on validation failures. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---