Has_many and belongs_to example?


#1

Hi!

If i have 2 tables i.e. product and images and product has_many images,
image belongs_to product - how to create _form.rhtml, new/create and
edit/update methods in product controller, so in a single form i can add
one product and MANY (let’s assume for now that this number is fixed)
images for this product?

Pleeeeease help me :slight_smile:


#2

g0nzo wrote:

Hi!

If i have 2 tables i.e. product and images and product has_many images,
image belongs_to product - how to create _form.rhtml, new/create and
edit/update methods in product controller, so in a single form i can add
one product and MANY (let’s assume for now that this number is fixed)
images for this product?

Pleeeeease help me :slight_smile:

Here are some snips that worked for me (thanks to the guys here);

CREATE TABLE cvs(
id INT not null AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(30) not null,
family_name VARCHAR(30) not null,
.
.
updated_on timestamp(14) not null
);

drop table if exists skills;
CREATE TABLE skills(
id INT not null AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(20) not null,
detail VARCHAR(200) not null,
cv_id int not null,
created_on timestamp(14) not null,
updated_on timestamp(14) not null,
constraint fk_skills_cv foreign key (cv_id) references cvs(id)
);

The at the command line;
script/generate model CV
script/generate model Skill

(in addition I generated controller & scaffold for each just to get
going;
script/generate controller CV_admin
script/generate controller Skill

script/generate scaffold CV CV_admin
script/generate scaffold skill skills
)

Then edit the 2 models created;
class CV < ActiveRecord::Base
has_many :skills
end

class Skill < ActiveRecord::Base
belongs_to :cv
end

to get the skills to be created from within the CV form;

Skills

<% for skill in @cv.skills %>

<%= h(skill.title) %><%= h(skill.detail) %>

<% end %>
<%= link_to "add_skill", :controller => "skills", :action => "new", :id => @cv %>

Inside the skills controller;

def new
@session[:cv_id] = params[:id]
@skill = Skill.new
end

def create
@cv = Cv.find(@session[:cv_id])
@cv.skills << Skill.new(params[:skill])
if @cv.save
flash[:notice] = ‘Skill was successfully created.’
redirect_to :action => ‘show’, :controller => ‘cv_admin’, :id =>
@cv
else
render :action => ‘new’
end
end

the @cv.save updates both the skills list and the cv and takes care of
all the associations for the foreign keys.

good luck.


#3

g0nzo wrote:

Thanks!!!

But one question: you have separate form for adding skills?
Would it be possible to add (many) skills directly via CV form, without
using separate form just for skills?

I believe so… I would just put the code from the new & create methods
for skills (from my example) into those for cv & obviously put the
skills form in the cv form, but having not tried this yet & as a newbie
myself, let me know how it works…


#4

Thanks!!!

But one question: you have separate form for adding skills?
Would it be possible to add (many) skills directly via CV form, without
using separate form just for skills?


#5

I believe you are doing the same thing I had to do for a person
having multiple visits for a given program. I am using AJAX links to
add and remove visits. My form looked like this…

<% unless @pgm_update.pgm_visits.empty? -%>
<% @pgm_update.pgm_visits.each_index do |index| %>









<%= plus_one(index) %>.   Start:

End:
<%= date_select “pgm_visit#{plus_one
(index)}”,“start”, :start_year => @program.start_date.year, :end_year
=> @program.end_date.year + 1, :order => [:month, :day, :year] %>

<%= date_select “pgm_visit#{plus_one
(index)}”,“ends”, :start_year => @program.start_date.year, :end_year
=> @program.end_date.year + 1, :order => [:month, :day, :year] %>

<% if @pgm_update.pgm_visits.size > 1 -%>
<%= link_to_remote ‘remove’,
:update => ‘visits’,
:url => {:action => :ajax_remove_visit, :id =>
index },
:with => “Form.serialize(‘application_form’)”
%>
<% end -%>


<% end -%>
<% else -%>

click ‘+’ to add a visit


<% end -%>

each visit instance variable (pgm_visit1…i) is dynamically
generated and set in the action with the following:

@pgm_update.pgm_visits.each_index do |i|
visit = i+1
instance_variable_set("@pgm_visit#{visit}".to_sym,
@pgm_update.pgm_visits[i])
end
if request.post?
@pgm_update.pgm_visits.each_index do |i|
visit = i+1
instance_variable_get("@pgm_visit#
{visit}".to_sym).attributes = params[“pgm_visit#{visit}”]
end
end

I can give more details on request

-John


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


#6

These examples have helped me a lot!

My problem is this, how do you UPDATE child records? Every tutorial
and book I see only addresses the parent/child saving issue in the New
method.

I can’t do a find for children, because I don’t know the child.id and
each parent will have at least 3 children.

John S. wrote:

I believe you are doing the same thing I had to do for a person
having multiple visits for a given program. I am using AJAX links to
add and remove visits. My form looked like this…

<% unless @pgm_update.pgm_visits.empty? -%>
<% @pgm_update.pgm_visits.each_index do |index| %>









<%= plus_one(index) %>.   Start:

End:
<%= date_select “pgm_visit#{plus_one
(index)}”,“start”, :start_year => @program.start_date.year, :end_year
=> @program.end_date.year + 1, :order => [:month, :day, :year] %>

<%= date_select “pgm_visit#{plus_one
(index)}”,“ends”, :start_year => @program.start_date.year, :end_year
=> @program.end_date.year + 1, :order => [:month, :day, :year] %>

<% if @pgm_update.pgm_visits.size > 1 -%>
<%= link_to_remote ‘remove’,
:update => ‘visits’,
:url => {:action => :ajax_remove_visit, :id =>
index },
:with => “Form.serialize(‘application_form’)”
%>
<% end -%>


<% end -%>
<% else -%>

click ‘+’ to add a visit


<% end -%>

each visit instance variable (pgm_visit1…i) is dynamically
generated and set in the action with the following:

@pgm_update.pgm_visits.each_index do |i|
visit = i+1
instance_variable_set("@pgm_visit#{visit}".to_sym,
@pgm_update.pgm_visits[i])
end
if request.post?
@pgm_update.pgm_visits.each_index do |i|
visit = i+1
instance_variable_get("@pgm_visit#
{visit}".to_sym).attributes = params[“pgm_visit#{visit}”]
end
end

I can give more details on request

-John


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