"undefined method `each'" error is derailing me

I was SO close to successfully updating my HABTM relationship!

Here’s my schema:

create_table “people”, :force => true do |t|
t.column “family_name”, :string
t.column “given_name”, :string
t.column “email”, :string
t.column “keitai_email”, :string
t.column “photo”, :binary
t.column “telephone_extension”, :integer
t.column “hashed_password”, :string
end

create_table “people_projects”, :force => true do |t|
t.column “person_id”, :integer
t.column “project_id”, :integer
end

create_table “projects”, :force => true do |t|
t.column “project_number”, :string
t.column “client_company”, :string
t.column “client_contact”, :string
t.column “contact_email”, :string
t.column “contact_phone”, :string
t.column “open_date”, :date
t.column “close_date”, :date
t.column “project_description”, :text
end

And my controller def:

def update
@project = Project.find(params[:id])
@project.people = Person.find(params[:addpersonid]) if
params[:addpersonid]
if @project.update_attributes(params[:project])
flash[:notice] = ‘Project was successfully updated.’
redirect_to :action => ‘show’, :id => @project
else
render :action => ‘edit’
end
end

And the code in the view that calls that def:

TEAM

<% team = Project.find(@id).people.find(:all) %> <% for p in @people -%>
<% if team.include?(p) %> <%= p.family_name %> <% else %> <%= button_to "add #{p.family_name}", :action => "update", :id => @id, :addpersonid => p.id %> <% end %>
<% end -%>

According to my best guess, everything should work now. But I suddenly
got this “undefined method `each’” error. I’ve done a search on my
controller and the word “each” doesn’t even exist in it. Does anybody
know what’s going on here?

Thanks
sean

On 5/30/07, Sean C. [email protected] wrote:

t.column "keitai_email",        :string

create_table “projects”, :force => true do |t|
And my controller def:
end
<%= p.family_name %>
got this “undefined method `each’” error. I’ve done a search on my
controller and the word “each” doesn’t even exist in it. Does anybody
know what’s going on here?

Thanks
sean

each is a method included with the Enumerable module. Many classes use
it,
including the internals of many rails classes.

I believe your issue is in the update method of the controller

def update
@project = Project.find(params[:id])
@project.people = Person.find(params[:addpersonid]) if
params[:addpersonid]
if @project.update_attributes(params[:project])
flash[:notice] = ‘Project was successfully updated.’
redirect_to :action => ‘show’, :id => @project
else
render :action => ‘edit’
end
end

It seems that you want to replace any existing persons with only one
person,
but you’ll need to wrap it in an array or similar. You could use

@project.people = [Person.find(params[:addpersonid])] if
params[:addpersonid]

since the = method on the association in a HABTM is looking for multiple
objects it will call each on it’s argument to add each person to the
association. ie
@project.people = [person1, person2, person3]

Will result somewhere in
[person1, person2, person3].each …

If what your after is to add another person to the projects people then
you
should use the contat method

@project.people << Person.find(params[:addpersonid]) if
params[:addpersonid]

HTH

Daniel

Can you post the actual error with line numbers?

You are referencing @id in your view, but it is never set in the
controller. You also don’t need to do a Project.find in the view. Do
it in the controller and reference the array in the view.

Shane

On 5/30/07, Sean C. [email protected] wrote:

t.column "photo",               :binary
t.column "project_number",      :string

end
<% else %>
controller and the word “each” doesn’t even exist in it. Does anybody
know what’s going on here?

Thanks
sean


Posted via http://www.ruby-forum.com/.


http://shanesbrain.net

On May 30, 2007, at 1:25 AM, Sean C. wrote:

<% for p in @people -%>

This is equivalent to:

<% @people.each do |p| -%>

and yet you have not assigned any value to the @people variable.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

Sorry guys! Forgot you might need the other def in the controller. Here
it is:

def show
project = Project.find_by_id(params[:id])
@id, @projectnumber, @client = project.id, project.project_number,
project.client_company
@description = project.project_description
@contactemail, @clientcontact, @contactphone =
project.contact_email, project.client_contact, project.contact_phone
@opendate, @closedate = project.open_date.strftime("%A, %B %d, %Y"),
project.close_date.strftime("%A, %B %d, %Y")
@people = Person.find(:all, :order => “family_name ASC”)
end

I will mash the keyboard some more and try Daniel’s excellent
recommendations in the meantime.

WOOHOO!
THANK YOU DANIEL!

That was it! just changing it from the equals operator to the contat
(concat?) operator did the trick.

I was sweating over possibly having to install mysql 5 for the past hour
too. Thanks to everybody.

Spoke too soon.

Strange - the controller is now writing records to the table, but there
is an oddity. It’s saving each habtm column with an id equal to the
person’s id, resulting in rails trying to create another record with the
same id if i try to to add someone who’s on one project to another
project.

To be clearer, if my table is set up like this:

id ---- person.id ---- project.id

then Rails is sending the same value to the table as both the id AND the
person.id, resulting in this (if we have five people total):

1 ---- 1 ---- 1
2 ---- 2 ---- 1
3 ---- 3 ---- 1
4 ---- 4 ---- 1
5 ---- 5 ---- 1

So if I try to add a person to another project, whose data I thought
would be sent as:
6 ---- 1 ---- 2

It is instead sent as:
1 ---- 1 ---- 2,

Resulting in an error.

So it seems Rails believes that I am sending an explicit id for the
habtm table when I’m actually not trying to do this. I didn’t even know
it was possible to do this, honestly.

On 5/30/07, Sean C. [email protected] wrote:

To be clearer, if my table is set up like this:
5 ---- 5 ---- 1
So it seems Rails believes that I am sending an explicit id for the
habtm table when I’m actually not trying to do this. I didn’t even know
it was possible to do this, honestly.

This is a problem with your join table. HABTM is a dumb join. The join
table is only the two id’s of the things to join. The join itself is
not a
rich model, and so the join model shouldn’t include an id column.

This is an issue with your table decleration for the join table

create_table “people_projects”, :force => true do |t|
t.column “person_id”, :integer
t.column “project_id”, :integer
end

Should be

create_table “people_projects”, :force => true, :id => false do |t|
t.column “person_id”, :integer
t.column “project_id”, :integer
end

Sorry should have picked that up before.

If you want to have an id column and therefore a rich join model, (ie
one
with it’s own logic and data) you should look at
has_many with the :through option

http://blog.hasmanythrough.com/ for more details

On 5/30/07, Sean C. [email protected] wrote:

WOOHOO!
THANK YOU DANIEL!

Your welcome.

That was it! just changing it from the equals operator to the contat

(concat?) operator did the trick.

I don’t think it’s actually called concat. I was thinking of
concatenate
but I’m not sure what it’s correct name is.

I’m happy that worked for you.

Daniel ----- wrote:

If you want to have an id column and therefore a rich join model, (ie
one
with it’s own logic and data) you should look at
has_many with the :through option

http://blog.hasmanythrough.com/ for more details

Thanks! But no, I don’t want a rich join model. Dumb is good.

So, just out of curiosity, would this “:id => false” statement be
something that I should include in every HABTM (the dumb ones, anyway)
declaration, just to be safe from now on?

Thanks again

Thanks Daniel. Everything is moving along swimmingly now.

Now I’m having trouble deleting a record. I can’t delete one like I
would an array element, I don’t think.

This is what I’ve got:

def removeFromProject
@project = Project.find(params[:projectid])
@project.people.find(params[:personid]).clear
redirect_to :action => ‘show’, :id => params[:projectid]
end

I tried using .delete() instead of clear, but no dice. Anybody know
where I’m going wrong?

Thanks
sean

Never mind! Got it!

def removeFromProject
@project = Project.find(params[:projectid])
person = Person.find(params[:personid])
@project.people.delete(person)
redirect_to :action => ‘show’, :id => params[:projectid]
end

Thanks everybody!

On 5/30/07, Sean C. [email protected] wrote:

Thanks! But no, I don’t want a rich join model. Dumb is good.

So, just out of curiosity, would this “:id => false” statement be
something that I should include in every HABTM (the dumb ones, anyway)
declaration, just to be safe from now on?

Thanks again

Yes, This just prevents the table from being created with an id column

On 6/1/07, Sean C. [email protected] wrote:

redirect_to :action => 'show', :id => params[:projectid]

end

I tried using .delete() instead of clear, but no dice. Anybody know
where I’m going wrong?

Thanks
sean

Sean,
You’re not really dealing with an array here, and if you do, you will
only
do so in memory at best. It will not persist.

In the docs

it says it should be
@project.people.delete( Person.find( params[:personid] ) )

Hope that gets you going.

Cheers
Daniel

Thanks Daniel - I’m getting the concept that it’s not technically an
array, but for the time being the only way for me to keep the concept
straight in my head is to treat it like one. Since I don’t have a
computer science background (though the more I learn about scripting,
the more I kick myself for not starting earlier - I took Comp Sci 101 in
college, had a kind of lazy prof who just sat back and watched me
struggle with the Pascal compiler all semester without helping, and
ended up writing off the entire field of study in disgust), I’m still
playing catch-up.

Anyway, thanks a lot.
sean

On 6/1/07, Sean C. [email protected] wrote:

playing catch-up.

Anyway, thanks a lot.
sean

Yes similar here. I’m sure it takes me a long time to get stuff
compared
with ppl with a computer science degree behind them… I’m a mechanical
engineer and just play with this in my spare time. Would be nice if it
was
otherwise…

Good luck with your project.

Daniel