Proper way to create an association


#1

All,

I’m looking for the “preferred” way to create an assocation between a
parent and a child record. I have read several documents and it seems
there are many ways to achieve this. Right now, I’m creating the child
record and obtaining the id from the parent to populate it. Somehow,
this feels wrong.

I have the agile book, but it is just different enough from my situation
that I’m left unsure how to do it correctly.

Scenario:

I have a view that contains a detail record for the parent. Below the
detail record, I show a list of child records. A user may create a new
child record.

At this point, the view will be taken to the new view for the child
controller and action. The controller is not the same as the controller
for the parent.

The way I do it now: In the new action for the child, I get the id of
the parent, query it out and set the parent_id column for the child
record.

It seems like I should be able to call something like Parent.Child.new
and have the values auto populated for the one-to-many. This would
drive it to my child view for my child controller. But I can’t get it
figured out.

Also, once my child record gets saved, I want to navigate back to the
parent detail view that the user was on before creating the new child
record.

This seems like a basic scenario, but I have been struggling with it.
The “Four Days on Rails” document shows it the way I have described.
The agile book shows a different process, but it assumes the record you
are associating is already created in the database. Just looking for
some pointers from the pro’s so that I get my project started on the
right track. I’ll have many scenarios just like this and want to do it
the proper way.

Your help is appreciated.

Michael


#2

No takers on this? I know the experts out there have a best practice
approach and I am hoping someone will share their wisdom with me. The
framework is very flexible and I want to ensure I am doing things the
proper way.

Your input is very appreciated…

Michael

Michael removed_email_address@domain.invalid wrote:
All,

I’m looking for the “preferred” way to create an assocation between a
parent and a child record. I have read several documents and it seems
there are many ways to achieve this. Right now, I’m creating the child
record and obtaining the id from the parent to populate it. Somehow,
this feels wrong.

I have the agile book, but it is just different enough from my situation
that I’m left unsure how to do it correctly.

Scenario:

I have a view that contains a detail record for the parent. Below the
detail record, I show a list of child records. A user may create a new
child record.

At this point, the view will be taken to the new view for the child
controller and action. The controller is not the same as the controller
for the parent.

The way I do it now: In the new action for the child, I get the id of
the parent, query it out and set the parent_id column for the child
record.

It seems like I should be able to call something like Parent.Child.new
and have the values auto populated for the one-to-many. This would
drive it to my child view for my child controller. But I can’t get it
figured out.

Also, once my child record gets saved, I want to navigate back to the
parent detail view that the user was on before creating the new child
record.

This seems like a basic scenario, but I have been struggling with it.
The “Four Days on Rails” document shows it the way I have described.
The agile book shows a different process, but it assumes the record you
are associating is already created in the database. Just looking for
some pointers from the pro’s so that I get my project started on the
right track. I’ll have many scenarios just like this and want to do it
the proper way.

Your help is appreciated.

Michael


#3

I am sure everyone is just very busy. I am brand new at this and have
not even been lurking on this list very long, but I can tell you how I
do it.

It seems like I should be able to call something like Parent.Child.new

Zactly… except its called Parent.Child.build(attributes = {}) or
Parent.Child.create(attributes = {}).

The build method returns a fresh child object with populated data.
The create method returns the same but already saved in the database.

Took me a while to get this too… even though it is of course basic
and simple. I really like the HowTo wiki, but often I have to study
the api to find what I need.

I think what you need is right here:
http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html#M000464

Like I said, I’m just learning this myself… and spending 12 - 16
hours a day on it… but its worth it. The only thing I miss about
PHP is the annotated documentation. But the beauty of Ruby and the
Rails framework, makes me happy to spend the extra time to find what I
know is there.

-=nathan

On 11/10/05, Michael removed_email_address@domain.invalid wrote:

Your help is appreciated.

Michael


Yahoo! FareChase - Search multiple travel sites in one click.


#4

completely untested and not even sure if this is what you are attempting
to
do…but i gave it a go :slight_smile:

class LeadController < ApplicationController
def show

load the specified lead

@lead = Lead.find(@params[:id])

in your show.rhtml view, show a link to create a new activity that

points
to :controller => “activity”, :action => “new”, :lead_id =>
@lead.idhttp://lead.id
end
end

class Activity Controller < ApplicationController
def new

create a new activity to use to generate form data

@activity = Activity.new(:lead_id => @params[:lead_id])

form in new.rhtml should point to :action => :create

and should include hidden field with lead id

hidden_field(:activity, :lead_id …)

end

def create

instantiate a new activity loaded with the form data

activity = Activity.new(@params[:activity])

save the activity

if activity.save
flash[:notice] = “activity created successfully”
else
flash[:error] = “could not save activity”
end
redirect_to :controller => “lead”, :action => “show”, :id =>
activity.lead_id
end
end


#5

Hi Nathan,

Thank you for the input. I am failing to grasp a simple concept and it
is frustrating!!! I wish I had a working example so that I could figure
out what I’m missing.

In your example below, you show the “build” and the “create” - but I am
missing how the values are getting populated in that.

Forgive me for a long email, but I want to describe my flow a little
better so that someone can fill in the gap(s). Your input may be very
valid, but since I’m missing something along the way I’m not able to tie
it together.

Parent A:
Child A
Child B

I build a view that shows the details of parent A (show record) and in a
table below that, on the same view, I provide a list of children that
relate to that parent.

Right below the list of Children, I have a button to create a new child
(child c in this case) for that parent.

Parent A controller = Leads
Parent B controller = Activity

When a user invokes the New button, the form currently does this:

start_form_tag :controller => ‘activity’, :action => ‘new’, :id => @lead

I have tried to change the controller to ‘lead’ and have a new action
along the lines of ‘new_activity’ and then call the build or create but
I don’t know how to get to the controller for the activity from here so
that I can utilize the “new” rhtml file that I have for it. Does that
make sense?

I need to create new activities from many different controllers (leads,
contacts, invoices, etc…). I don’t want to repeat the code across all
of them??? Is my structure wrong? I know for sure I have something
wrong or am missing a very basic concept. If someone knows of a working
sample that has similar flow then that would be great. The example from
the agile book where you have a Cart and Add line items to it isn’t the
same because the line items already exist in the database.

Thanks to anyone that can set me straight!

Michael

nathan removed_email_address@domain.invalid wrote:
I am sure everyone is just very busy. I am brand new at this and have
not even been lurking on this list very long, but I can tell you how I
do it.

It seems like I should be able to call something like Parent.Child.new

Zactly… except its called Parent.Child.build(attributes = {}) or
Parent.Child.create(attributes = {}).

The build method returns a fresh child object with populated data.
The create method returns the same but already saved in the database.

Took me a while to get this too… even though it is of course basic
and simple. I really like the HowTo wiki, but often I have to study
the api to find what I need.

I think what you need is right here:
http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html#M000464

Like I said, I’m just learning this myself… and spending 12 - 16
hours a day on it… but its worth it. The only thing I miss about
PHP is the annotated documentation. But the beauty of Ruby and the
Rails framework, makes me happy to spend the extra time to find what I
know is there.

-=nathan

On 11/10/05, Michael wrote:

Your help is appreciated.

Michael


Yahoo! FareChase - Search multiple travel sites in one click.


#6

Hi Chris,

This is almost exactly what I have done. But doesn’t it look backwards?
This is taking the child and associating it to the parent upon child
creation. I know it works, but instead of having to keep track of the
parent id’s I was thinking there is some way for the parent to
instantiate a child record creation and do this for me.

Imagine what my Activity controller new and create actions are going to
look like once I add leads, contacts, accounts, etc… - basically every
parent that an activity can be associated with. I’ll have to check a
bunch of different params to know which one I’m creating the child
against.

If this is the correct way to do it then great. I feel it is backwards
though and that is why I am soliciting this group for advice on best
practices.

Suggestions?

Thanks,

Michael

Chris H. removed_email_address@domain.invalid wrote:
completely untested and not even sure if this is what you are attempting
to do…but i gave it a go :slight_smile:

class LeadController < ApplicationController
def show
# load the specified lead
@lead = Lead.find(@params[:id])
# in your show.rhtml view, show a link to create a new activity that
points to :controller => “activity”, :action => “new”, :lead_id =>
@lead.id
end
end

class Activity Controller < ApplicationController
def new
# create a new activity to use to generate form data
@activity = Activity.new(:lead_id => @params[:lead_id])

# form in new.rhtml should point to :action => :create
# and should include hidden field with lead id
# hidden_field(:activity, :lead_id ...)

end

def create
# instantiate a new activity loaded with the form data
activity = Activity.new(@params[:activity])
# save the activity
if activity.save
flash[:notice] = “activity created successfully”
else
flash[:error] = “could not save activity”
end
redirect_to :controller => “lead”, :action => “show”, :id =>
activity.lead_id
end
end

On 11/10/05, Michael removed_email_address@domain.invalid wrote:Hi Nathan,

Thank you for the input. I am failing to grasp a simple concept and it
is frustrating!!! I wish I had a working example so that I could figure
out what I’m missing.

In your example below, you show the “build” and the “create” - but I am
missing how the values are getting populated in that.

Forgive me for a long email, but I want to describe my flow a little
better so that someone can fill in the gap(s). Your input may be very
valid, but since I’m missing something along the way I’m not able to tie
it together.

Parent A:
Child A
Child B

I build a view that shows the details of parent A (show record) and in a
table below that, on the same view, I provide a list of children that
relate to that parent.

Right below the list of Children, I have a button to create a new child
(child c in this case) for that parent.

Parent A controller = Leads
Parent B controller = Activity

When a user invokes the New button, the form currently does this:

start_form_tag
:controller => ‘activity’, :action => ‘new’, :id => @lead

I have tried to change the controller to ‘lead’ and have a new action
along the lines of ‘new_activity’ and then call the build or create but
I don’t know how to get to the controller for the activity from here so
that I can utilize the “new” rhtml file that I have for it. Does that
make sense?

I need to create new activities from many different controllers (leads,
contacts, invoices, etc…). I don’t want to repeat the code across all
of them??? Is my structure wrong? I know for sure I have something
wrong or am missing a very basic concept. If someone knows of a working
sample that has similar flow then that would be great. The example from
the agile book where you have a Cart and Add line items to it isn’t the
same because the line items already exist in the database.

Thanks to anyone that can set me straight!

Michael

nathan removed_email_address@domain.invalid wrote:
I am sure everyone is just very busy. I am brand new at this and have
not even been lurking on this list very long, but I can tell you how I
do it.

It seems like I should be able to call something like Parent.Child.new

Zactly… except its called Parent.Child.build(attributes = {}) or
Parent.Child.create(attributes = {}).

The build method returns a fresh child object with populated data.
The create method returns the same but already saved in the database.

Took me a while to get this too… even though it is of course basic
and simple. I really like the HowTo wiki, but often I have to study
the api to find what I need.

I think what you need is right here:
http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html#M000464

Like I said, I’m just learning this myself… and spending 12 - 16
h ours a day on it… but its worth it. The only thing I miss about
PHP is the annotated documentation. But the beauty of Ruby and the
Rails framework, makes me happy to spend the extra time to find what I
know is there.

-=nathan

On 11/10/05, Michael wrote:

Your help is appreciated.

Michael


Yahoo! FareChase - Search multiple travel sites in one click.


Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails


Yahoo! FareChase - Search multiple travel sites in one click.


#7

Michael,

Here is a simple example that worked for me (actually untested as I
removed
unnecessary code in this example for brevity):

MySql Database:

CREATE TABLE contacts (
id int(11) NOT NULL auto_increment,
first_name varchar(255) NOT NULL default ‘’,
last_name varchar(255) NOT NULL default ‘’,
PRIMARY KEY (id)
) ;

CREATE TABLE emails (
id int(11) NOT NULL auto_increment,
contact_id int(11) NOT NULL default ‘0’,
address varchar(255) NOT NULL default ‘’,
PRIMARY KEY (id)
) ;

Models:

class Contact < ActiveRecord::Base
has_many :emails
end

class Email < ActiveRecord::Base
belongs_to :contact
end

Controller:

def add_email
@contact = Contact.find params[:id]
@contact.emails.create params[:email]
flash[:notice] = ‘Email was successfully added.’
render :action => ‘show’
end

View:

<%= start_form_tag :action => ‘add_email’, :id => @contact %>
Email:
<%= text_field ‘email’, ‘address’ %>
<%= submit_tag “Add Email” %>
<%= end_form_tag %>

Hope this helps,
-=nathan


#8

Hi Micheal,

Have you had a look at the
acts_as_treehttp://api.rubyonrails.com/classes/ActiveRecord/Acts/Tree/ClassMethods.html#M000478act?
It allows a similar set of functionality to what you have described.

Cheers
Dan


#9

Thank you Nathan for that sample… Very much appreciated. I think it
provided an answer to my problem.

Michael

nathan removed_email_address@domain.invalid wrote:
Michael,

Here is a simple example that worked for me (actually untested as I
removed unnecessary code in this example for brevity):

MySql Database:

CREATE TABLE contacts (
id int(11) NOT NULL auto_increment,
first_name varchar(255) NOT NULL default ‘’,
last_name varchar(255) NOT NULL default ‘’,
PRIMARY KEY (id)
) ;

CREATE TABLE emails (
id int(11) NOT NULL auto_increment,
contact_id int(11) NOT NULL default ‘0’,
address varchar(255) NOT NULL default ‘’,
PRIMARY KEY (id)
) ;

Models:

class Contact < ActiveRecord::Base
has_many :emails
end

class Email < ActiveRecord::Base
belongs_to :contact
end

Controller:

def add_email
@contact = Contact.find params[:id]
@contact.emails.create params[:email]
flash[:notice] = ‘Email was successfully added.’
render :action => ‘show’
end

View:

<%= start_form_tag :action => ‘add_email’, :id => @contact %>
Email:
<%= text_field ‘email’, ‘address’ %>
<%= submit_tag “Add Email” %>
<%= end_form_tag %>

Hope this helps,
-=nathan


#10

Thank you Dan…I’ll look into this and see if applicable.

Michael

Liquid removed_email_address@domain.invalid wrote:
Hi Micheal,

Have you had a look at the acts_as_tree act? It allows a similar set of
functionality to what you have described.

Cheers
Dan

On 11/11/05, nathan removed_email_address@domain.invalid wrote:Michael,

Here is a simple example that worked for me (actually untested as I
removed unnecessary code in this example for brevity):

MySql Database:

CREATE TABLE contacts (
id int(11) NOT NULL auto_increment,
first_name varchar(255) NOT NULL default ‘’,
last_name varchar(255) NOT NULL default ‘’,
PRIMARY KEY (id)
) ;

CREATE TABLE emails (
id int(11) NOT NULL auto_increment,
contact_id int(11) NOT NULL default ‘0’,
address varchar(255) NOT NULL default ‘’,
PRIMARY KEY (id)
) ;

Models:

class Contact < ActiveRecord::Base
has_many :emails
end

class Email < ActiveRecord::Base
belongs_to :contact
end

Controller:

def add_email
@contact = Contact.find params[:id]
@contact.emails.create params[:email]
flash[:notice] = ‘Email was successfully added.’
render :action => ‘show’
end

View:

<%= start_form_tag :action => ‘add_email’, :id => @contact %>
Email:
<%= text_field ‘email’, ‘address’ %>
<%= submit_tag “Add Email” %>
<%= end_form_tag %>

Hope this helps,
-=nathan