# Save related models from one form

**URL:** <https://www.ruby-forum.com/t/save-related-models-from-one-form/56278>\
**Category:** Rails\
**Created:** [March 29, 2006, 11:38pm UTC](https://www.ruby-forum.com/t/save-related-models-from-one-form/56278 "2006-03-29T23:38:56Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![daniel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3ec8ea/32.png) [@daniel](https://www.ruby-forum.com/u/daniel)\
**Post date:** [March 29, 2006, 11:38pm UTC](https://www.ruby-forum.com/t/save-related-models-from-one-form/56278/1 "2006-03-29T23:38:56Z")

</div>

I have three tables customers, indentities and people. I hav ecreated  
models for them. The are connected with foreign keys and  
has\_many/belongs\_to in this fashion:

customers has\_many: identities  
identities belongs\_to: customer  
identities has\_many: people  
people belongs\_to: identities

Now, I have a form in which I would like to create db entries for the  
three tables. customers have a password field that needs to be equal to  
the params[:passwordconfirm], otherwise none of the models should be  
saved to the db.

I also have some data checks (validated\_presence\_of and  
validates\_uniqueness\_of) in the models.

If the data checks or password confirmation fails, I want that the form  
i displayed again so that the user can correct the errors. Else the data  
shoud be saved to the db. If I input data in all required fields all is  
fine, but…

My problems are:

1. If i input valid data in the required field, but type the  
passwordconfirmation so that it will fail I get the error message:  
ArgumentError which I guess has something to do with the “raise”-line  
below.

2. If I omitt some of the required fields I get the following error  
message:  
ActiveRecord::StatementInvalid …Column ‘customer\_id’ cannot be null:  
INSERT INTO identities…

The controller action looks like this. I guess the code inside the  
transaction block contains errors… however I would need some help in  
finding out whats wrong. Please help me!

def create\_data  
@customer = Customer.new  
@identity = Identity.new  
@person = Person.new

```
    @identity.customer = @customer
    @person.identity = @identity

    if request.post?
        @pwdmismatch = false
        @customer.attributes = params[:customer]
        @identity.attributes = params[:identity]
        @person.attributes = params[:person]
        undigestedPassword = @customer.password
        @customer.password = MD5.md5(undigestedPassword).hexdigest
        begin
            @customer.transaction(@customer, @identity, @person) do
                @customer.save
                @identity.save
                @person.save

                if(undigestedPassword != params[:passwordconfirm])
                    @pwdmismatch = true
                end

                raise ActiveRecord::RecordInvalid unless

```

@customer.valid? && @identity.valid? && @person.valid? && (@pwdmismatch  
== false)  
login(@customer.username, undigestedPassword,  
“identity”) #Login and redirect the user to the selected identity  
end #end transaction  
rescue ActiveRecord::RecordInvalid  
end  
end  
end #end of create data

My rhtml-file uses “error\_message\_on”, “error\_messages\_for” and checking  
if pwdmismatch is true to mark errors in the input data.

Like I said, I would need some help on this.

Best regards,  
Daniel

---

<div class="post-metadata">

**Author:** ![daniel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3ec8ea/32.png) [@daniel](https://www.ruby-forum.com/u/daniel)\
**Post date:** [March 30, 2006, 1:28am UTC](https://www.ruby-forum.com/t/save-related-models-from-one-form/56278/2 "2006-03-30T01:28:29Z")

</div>

> 1. If i input valid data in the required field, but type the  
> passwordconfirmation so that it will fail I get the error message:  
> ArgumentError which I guess has something to do with the “raise”-line  
> below.  
> See below for the fix.  
> def create\_data  
> @customer = Customer.new  
> @identity = Identity.new  
> @person = Person.new

These last two lines won’t do what you want them to do. You cannot  
set a relationship like this until the record with the foreign key  
has been saved. Eg.  
@customer.save  
@identity.costomer = @customer  
If you jump the gun like you did then @customer.id will be nil so  
@identity.customer\_id will be nil. Same with @identity.id and  
@person.identity\_id. But doing what I suggest is a paradox since you  
don’t want to save it yet. I struggle with this same paradox all the  
time. No one has ever given me a good solutions, only hacks (see hack  
below).

> (@pwdmismatch  
> == false)  
> @customer.save calls @customer.valid? and returns the result. You are  
> repeating validation several times here.

# The grand solution/hack is something like:

def create\_data  
@customer = Customer.new  
@identity = Identity.new  
@person = Person.new

```
     #too soon for this to work
     #@identity.customer = @customer
     #@person.identity = @identity

     if request.post?
         @pwdmismatch = false
         @customer.attributes = params[:customer]
         @identity.attributes = params[:identity]
         @person.attributes = params[:person]
         undigestedPassword = @customer.password
         @customer.password = MD5.md5(undigestedPassword).hexdigest
         begin
             @customer.transaction(@customer, @identity, @person) do
                 customer_valid = @customer.save
                 @identity.customer = @customer
                 identity_valid = @identity.save
                 @person.identity = @identity
                 person_valid = @person.save

                 if(undigestedPassword != params[:passwordconfirm])
                     @pwdmismatch = true
                 end

                 raise ActiveRecord::RecordInvalid.new(@customer)

```

# unless customer\_valid && identity\_valid && person\_valid && (@pwdmismatch == false) login(@customer.username, undigestedPassword, “identity”) #Login and redirect the user to the selected identity end #end transaction rescue ActiveRecord::RecordInvalid end end end #end of create data

-John

–  
John S.  
Computing Staff - Webmaster  
Kavli Institute for Theoretical Physics  
University of California, Santa Barbara  
removed\_email\_address@domain.invalid  
(805) 893-6307

---

<div class="post-metadata">

**Author:** ![daniel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3ec8ea/32.png) [@daniel](https://www.ruby-forum.com/u/daniel)\
**Post date:** [March 30, 2006, 10:21am UTC](https://www.ruby-forum.com/t/save-related-models-from-one-form/56278/3 "2006-03-30T10:21:34Z")

</div>

Thank you for taking your time to explain this. I really appreciate it!

This solution only works if I remove the “not null”-checks in all  
foreign key fields in the affected tables (customer, identities,  
people)(mySQL). I guess I dont need to have the db check for “not null”  
when I have the validation in the models. Is that right?

It feels somewhat weird that it wont work if I have the checks for “not  
null”-foreign keys in the database. Is it not possible to have both  
validation in models and that the db checks that the foreign keys are  
not null?

If I use “not null” for the foreign keys in the database and  
validate\_presence\_of the foreign keys in the models as well, I get a SQL  
error saying something about foreign key cant be null. It seems like the  
model validation is ignored, rails tries to save the record straight to  
the db which causes the error to pop up.

//Daniel
