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 -~----------~----~----~----~------~----~------~--~---