Hi, I have a situation I''m hoping someone out there may be able to shed some light on. I have a Rails app (2.1.0 on Ruby 1.8.7) with a wizard-based sign up process, that has recently been changed from storing incremental data in the database to having a medium sized object graph living in the user session until the user completes the entire sign up process (this is a business requirement now). After the user commits all relevant data, I''m now calling save! on the top-level object to save all the rows at once. However, when the call to save! happens--and because I have two objects that have a belongs_to association, each pointing to other in addition to the normal bidirectional association--I end up in an endless validation loop. Funny thing is, when I was incrementally saving the data, this issue never arose--another way to put it, those relationships never caused a problem when saving/retrieving already-existing rows. In the model tier, I have the following classes defined: class PrimaryAccount < Account has_many :payment_methods, :foreign_key => "account_id" #using single table inheritance, which is why foreign key is not "primary_account_id" belongs_to :current_payment_method, :class_name => "PaymentMethod", :foreign_key => "current_payment_method_id" #points to same table, so I can have many payment_methods, but also mark as being the current one to bill ... class PaymentMethod < ActiveRecord::Base belongs_to :account #normal bidirectional association ... class CreditCard < PaymentMethod ... In the controller tier, I have a session object that--on the final step--loads an Account model object based on the current session state, and then calls save! on that model: class PrimaryAccountUser < User attr_reader :credit_card def initialize(service_id) @credit_card = {} #hash for storing credit card attributes end def persist_to_database add_session_data_to_account(PrimaryAccount.new) account.save! @id = account.id return account end private def add_session_data_to_account(account) #adds the impl-specific things to the account if(!@credit_card.blank?) card = CreditCard.new do |cc| cc.account_type = @credit_card[:type] cc.account_name = @credit_card[:name] cc.account_number = @credit_card[:number] cc.cvv = @credit_card[:cvv] cc.account_expiration = @credit_card[:expiration] cc.address = @credit_card[:address] cc.city = @credit_card[:city] cc.state = @credit_card[:state] cc.zip = @credit_card[:zip] cc.country = @credit_card[:country] cc.phone = @credit_card[:phone] end #strange...this won''t populate the account_id on save! account.payment_methods << card #again, if I don''t do this, then the payment_method won''t have a populated account_id on save! card.account = account #doing this causes the endless validation loop account.current_payment_method = card end return account end Am I crazy for thinking this ought to work? Thanks in advance, Ryan Frith ralafapa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Brian Hogan
2008-Jul-16 03:16 UTC
Re: belongs_to causing endless loop on first call to save!
It just seems way too overengineered to me. When you add a card to the system, just add the card In the controller, for example: def create card = Card.new(params[:card] card.account_id = session[:user_id] # or current_user.id or wherever you store the id of the currently logged in user. if account.save ... else ... end end No need to do all that account << card stuff because the web is stateless. When it''s saved, you''re going to redirect them, a new request will be made by your user, and the records get queried again. Plus you save a ton of overhead. just my .02. Or maybe I''m oversimplifying your situation, but I just like to keep things as simple as possible. On Tue, Jul 15, 2008 at 7:28 PM, Ryan Frith <ralafapa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hi, > > I have a situation I''m hoping someone out there may be able to shed some > light on. I have a Rails app (2.1.0 on Ruby 1.8.7) with a wizard-based sign > up process, that has recently been changed from storing incremental data in > the database to having a medium sized object graph living in the user > session until the user completes the entire sign up process (this is a > business requirement now). After the user commits all relevant data, I''m > now calling save! on the top-level object to save all the rows at once. > However, when the call to save! happens--and because I have two objects that > have a belongs_to association, each pointing to other in addition to the > normal bidirectional association--I end up in an endless validation loop. > Funny thing is, when I was incrementally saving the data, this issue never > arose--another way to put it, those relationships never caused a problem > when saving/retrieving already-existing rows. > > In the model tier, I have the following classes defined: > > > class PrimaryAccount < Account > has_many :payment_methods, :foreign_key => "account_id" #using single > table inheritance, which is why foreign key is not "primary_account_id" > belongs_to :current_payment_method, :class_name => "PaymentMethod", > :foreign_key => "current_payment_method_id" #points to same table, so I can > have many payment_methods, but also mark as being the current one to bill > ... > > > class PaymentMethod < ActiveRecord::Base > belongs_to :account #normal bidirectional association > ... > > > class CreditCard < PaymentMethod > ... > > > In the controller tier, I have a session object that--on the final > step--loads an Account model object based on the current session state, and > then calls save! on that model: > > > class PrimaryAccountUser < User > > attr_reader :credit_card > > def initialize(service_id) > @credit_card = {} #hash for storing credit card attributes > end > > def persist_to_database > add_session_data_to_account(PrimaryAccount.new) > account.save! > @id = account.id > return account > end > > > private > > def add_session_data_to_account(account) #adds the impl-specific things > to the account > > if(!@credit_card.blank?) > card = CreditCard.new do |cc| > cc.account_type = @credit_card[:type] > cc.account_name = @credit_card[:name] > cc.account_number = @credit_card[:number] > cc.cvv = @credit_card[:cvv] > cc.account_expiration = @credit_card[:expiration] > cc.address = @credit_card[:address] > cc.city = @credit_card[:city] > cc.state = @credit_card[:state] > cc.zip = @credit_card[:zip] > cc.country = @credit_card[:country] > cc.phone = @credit_card[:phone] > end > > #strange...this won''t populate the account_id on save! > account.payment_methods << card > > #again, if I don''t do this, then the payment_method won''t have a > populated account_id on save! > card.account = account > > #doing this causes the endless validation loop > account.current_payment_method = card > > end > > return account > > end > > > Am I crazy for thinking this ought to work? > > > Thanks in advance, > > Ryan Frith > ralafapa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org > > > > >--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Ryan Frith
2008-Jul-16 05:08 UTC
Re: belongs_to causing endless loop on first call to save!
Maybe you didn''t see the fine print--I''m saving the entire object graph at once; there is no session[:user].id or current_user. I greatly simplified the code for the sake of brevity, but all the objects get assembled in the final sign-up step from state stored in the session over many screens (wizard) and then all the objects in the graph get persisted from the call to the top-level object''s save! method. This was a design decision to not save session state to DB in between requests for the sign up process. Anyways, the issue may be related to this one: http://dev.rubyonrails.org/ticket/1796 Anyone else have any ideas? Thanks, Ryan On Jul 15, 11:16 pm, "Brian Hogan" <bpho...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> It just seems way too overengineered to me. When you add a card to the > system, just add the card > > In the controller, for example: > > def create > card = Card.new(params[:card] > card.account_id = session[:user_id] # or current_user.id or wherever > you store the id of the currently logged in user. > if account.save > ... > else > ... > end > end > > No need to do all that account << card stuff because the web is stateless. > When it''s saved, you''re going to redirect them, a new request will be made > by your user, and the records get queried again. Plus you save a ton of > overhead. > > just my .02. > > Or maybe I''m oversimplifying your situation, but I just like to keep things > as simple as possible. > > On Tue, Jul 15, 2008 at 7:28 PM, Ryan Frith <ralaf...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > Hi, > > > I have a situation I''m hoping someone out there may be able to shed some > > light on. I have a Rails app (2.1.0 on Ruby 1.8.7) with a wizard-based sign > > up process, that has recently been changed from storing incremental data in > > the database to having a medium sized object graph living in the user > > session until the user completes the entire sign up process (this is a > > business requirement now). After the user commits all relevant data, I''m > > now calling save! on the top-level object to save all the rows at once. > > However, when the call to save! happens--and because I have two objects that > > have a belongs_to association, each pointing to other in addition to the > > normal bidirectional association--I end up in an endless validation loop. > > Funny thing is, when I was incrementally saving the data, this issue never > > arose--another way to put it, those relationships never caused a problem > > when saving/retrieving already-existing rows. > > > In the model tier, I have the following classes defined: > > > class PrimaryAccount < Account > > has_many :payment_methods, :foreign_key => "account_id" #using single > > table inheritance, which is why foreign key is not "primary_account_id" > > belongs_to :current_payment_method, :class_name => "PaymentMethod", > > :foreign_key => "current_payment_method_id" #points to same table, so I can > > have many payment_methods, but also mark as being the current one to bill > > ... > > > class PaymentMethod < ActiveRecord::Base > > belongs_to :account #normal bidirectional association > > ... > > > class CreditCard < PaymentMethod > > ... > > > In the controller tier, I have a session object that--on the final > > step--loads an Account model object based on the current session state, and > > then calls save! on that model: > > > class PrimaryAccountUser < User > > > attr_reader :credit_card > > > def initialize(service_id) > > @credit_card = {} #hash for storing credit card attributes > > end > > > def persist_to_database > > add_session_data_to_account(PrimaryAccount.new) > > account.save! > > @id = account.id > > return account > > end > > > private > > > def add_session_data_to_account(account) #adds the impl-specific things > > to the account > > > if(!@credit_card.blank?) > > card = CreditCard.new do |cc| > > cc.account_type = @credit_card[:type] > > cc.account_name = @credit_card[:name] > > cc.account_number = @credit_card[:number] > > cc.cvv = @credit_card[:cvv] > > cc.account_expiration = @credit_card[:expiration] > > cc.address = @credit_card[:address] > > cc.city = @credit_card[:city] > > cc.state = @credit_card[:state] > > cc.zip = @credit_card[:zip] > > cc.country = @credit_card[:country] > > cc.phone = @credit_card[:phone] > > end > > > #strange...this won''t populate the account_id on save! > > account.payment_methods << card > > > #again, if I don''t do this, then the payment_method won''t have a > > populated account_id on save! > > card.account = account > > > #doing this causes the endless validation loop > > account.current_payment_method = card > > > end > > > return account > > > end > > > Am I crazy for thinking this ought to work? > > > Thanks in advance, > > > Ryan Frith > > ralaf...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---