Note that there are some explanatory texts on larger screens.

plurals
  1. PORails - unpersisted parent needs to find candidate children and assign them to itself. Then display "new" form
    primarykey
    data
    text
    <p>This code shows what I'd like to do, but of course won't work because the Parent does not yet have an id:</p> <pre><code>class Parent &lt; ActiveRecord::Base has_many :children after_initialize :find_children, :if =&gt; Proc.new {|parent| parent.new_record?} private def find_children Child.where("blah blah blah").each do |child| child.parent = self #etc, etc, etc end end end </code></pre> <p>It's almost as if my controller's "new" action needs to save the Parent before displaying the new form. This doesn't feel right. What is a good approach to this problem?</p> <p><strong>Update</strong></p> <p>The child objects in my specific case are BillTransactions (think fees and credits) and the parents are Bills. Throughout a billing period, these transactions are accrued on an Account. At the end of the billing period, the user creates a bill for a given period, hence the need for a bill to find its children when it's created. </p> <p>I've been thinking about this some more after I posted the question. Since the Bill and BillTransactions can exist in many different states (pending, draft, active, emailed, etc) I'm going to use a state machine to manage the object's lifecycle. So far this is what I've come up with:</p> <pre><code>class Bill &lt; ActiveRecord::Base belongs_to :account has_many :bill_transactions attr_accessible :account, :bill_period_start, :bill_period_end after_initialize :find_fees, :if =&gt; Proc.new {|bill| bill.new_record?} validates_presence_of :account, :bill_period_start, :bill_period_end state_machine :initial =&gt; :pending do after_transition :pending =&gt; :canceled, :do =&gt; :destroy_self before_transition :active =&gt; :emailed, :do =&gt; :email_bill event :save_draft do transition :pending =&gt; :draft end event :activate do transition [:pending, :draft] =&gt; :active end event :email do transition :active =&gt; :emailed end event :apply_payment do transition [:active, :emailed] =&gt; :partial transition [:active, :emailed, :partial] =&gt; :paid end event :cancel do transition [:pending, :draft] =&gt; :canceled end end private def find_fees self.save unless [account, bill_period_start, bill_period_end].any? {|attr| attr.nil? } BillTransaction.where(:account_id =&gt; account.id, :transaction_date =&gt; bill_period_start..bill_period_end, :transaction_type =&gt; BillTransaction::TRANS_TYPES['Fee']).each do |fee| fee.stage self end end end def destroy_self self.bill_transactions.each do |trans| trans.unstage end self.destroy end end </code></pre> <p>So after a Bill is initialized for the first time, it basically saves itself, finds all relevant transactions, and "stages" them. This means BillTransaction's state is set to staged (which can transition back to unbilled if the new bill is destroyed) and its bill_id is set to the current Bill's id. You can see that if a Bill in the pending state is canceled, all of the transactions are unstaged (returned to the unbilled state). </p> <p>The problem with this solution is that sending a GET request to BillsController#new is supposed to be idempotent. This solution isn't strictly idempotent and I'm having a hard time seeing how I can ensure that the server's state will be rolled back if the user navigates away from the new form.</p> <p>Am I heading down a painful path here?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload