Tuesday, January 03, 2006

Multiple Record Forms for Ruby on Rails

********************UPDATE**********************************
I have moved to a new blog location and moved my blogger posts to http://thebitt.com

I have also created a zip file of multi-record app which you can find at http://thebitt.com/2006/01/03/multiple-record-forms-for-ruby-on-rails/

**************************************************************

I have been experimenting with creating a new goal management application using Ruby on Rails. The first challenge has been creating a signup application that takes account information and account owner information and then updates both an account and an user model. I couldn't find any examples on this that I could understand so I thought I would put up a short example of a working app.

First the database - two tables Account and User

  • Account has two fields
    • id
    • name


  • User has four fields
    • id
    • first_name
    • last_name
    • account_id
The models

Account Model
class Account < ActiveRecord::Base
has_many :users
validates_presence_of :name
validates_uniqueness_of :name
validates_length_of :name, :maximum => 100
end


User Model

class User < ActiveRecord::Base
belongs_to :account
validates_presence_of :first_name, :last_name
validates_uniqueness_of :first_name
end


The view

<h1>New account</h1>
<%= start_form_tag :action => 'create' %>
<%= error_messages_for 'account' %>
<!--[form:account]-->
<p><label for="account_name">Name</label><br/>
<%= text_field 'account', 'name' %></p>
<!--[eoform:account]-->

<%= error_messages_for 'user' %>
<!--[form:user]-->
<p><label for="user_first_name">First name</label><br/>
<%= text_field 'user', 'first_name' %></p>


<p><label for="user_last_name">Last name</label><br/>
<%= text_field 'user', 'last_name' %></p>
<!--[eoform:user]-->
<%= submit_tag "Create" %>
<%= end_form_tag %>

<%= link_to 'Back', :action => 'list' %>


The controller - Signup
class SignupController < ApplicationController

model :user
model :account


def index
new
render :action => 'new'
end


def new
@account = Account.new(@params['account'])
@user= User.new(@params['yser'])
end


def create
@account = Account.new(@params['account'])
@user = User.new(@params['user'])
@account.valid?
@user.valid?
if @account.valid? && @user.valid?
name = @account.name
@account.save
@account = Account.find_by_name(name)
@account.users << @user
flash[:notice] = 'Account was successfully created.'
redirect_to :action => 'new'
else
render :action => 'new'
end
end
end


I haven't figured out how to consolidate the validation error messages - If anybody knows how please let me know.

7 Comments:

Blogger Alex said...

I thought about that. I can drop the first one @account.valid?, but I need to make sure @user.valid? gets called so I get all the error messages. When @account.valid? fails in the if statement @user.valid? never gets called. Maybe something like

if @user.valid? uservalid = yes
if @account.valid? && uservalid == yes

might work and reduce calls to the model.

9:14 AM, January 04, 2006  
Blogger Doug Bromley said...

You're an absolute legend. I have the Agile Web Development with Rails book but I needed a clear and precise example of how to do this. Precisely the short, sweet little example I needed!! You wouldn't believe how much this has been frustrating me.

Thanks again.

Oh and btw. My 'tea blog' account isn't my main one. Its actually here: blog.straw-dogs.co.uk

10:14 AM, January 26, 2006  
Blogger Kilka said...

Hey Alex,

Thanks for the post. It's proven to be very helpful. Unfortunately, I can't seem to get the following to work:

@account.users << @user

Rails complains that the users variable is an unitialized constant. I was only able to work around this by explictily assigning the foreign key in users and explicitly saving @users.

Any advice would be appreciated.

Thanks,
-Jeremie.

10:46 AM, July 28, 2006  
Blogger Alex said...

I'm not sure what the problem is. It's been a while since I posted this. One thing that occurs to me is to check is to see if all of your models/variables have the plurals /singulars set right.

5:04 PM, August 01, 2006  
Blogger Steve said...

This is really useful - its so hard to find an example of this kind of update - and something I'd think just about everyone is going to need to do as soon as you get past the Hello World program. One thing that would really clarify things for me - what are the file names? Is the view new.rhtml?

11:12 PM, August 11, 2006  
Blogger Alex said...

yes the views file name is new.rhtml and it sits in a folder under views called signup

5:43 PM, August 26, 2006  
Blogger marcos9000 said...

In trying to get this to work:

@account.users << @user

... both sides of the association must be saved before this will work. I believe you only saved the account, and not the user. Therefore the join table does not have anything to refer to on the 'user side.'

7:11 AM, August 24, 2007  

Post a Comment

<< Home