Collection_select fails to work for "edit" but works great for "new"

Hi, all,

I setup a drop down box that has data populated by the database.

This is for a simple application where by I am trying to add a new
“Part”.
A part has a category and sub category.
The latter is optional.

When a category has been selected, an ajax query is made to the
database backend to
extract the subcategory options available for the selected category.

This has been implemented and works great for the task of adding a new
“Part” entry (ie. http://localhost:3000/parts/new) .

I did it by refering to the explanation in
http://shiningthrough.co.uk/blog/show/6.
It was good.

Nevertheless, when I need to edit a given part (ie.
http://localhost:3000/parts/22/edit),
I keep getting this silly error message below.
“undefined method `map’ for “#Category:0x103231d20”:Category”.

This is the full extract of the error messages:

============Extract Begin===============================
NoMethodError in Parts#edit

Showing app/views/categories/_form.html.erb where line #3 raised:

undefined method `map’ for “#Category:0x1036113c8”:Category

Extracted source (around line #3):

1: <%= label :category, :id, ‘Category’ %>

2: <%= collection_select(
3: :part,
4: ‘category_id’,
5: @categories,
6: :id,

Trace of template inclusion: app/views/parts/edit.html.erb
============Extract End===============================

Here’s what my other files look like:

app/views/parts/new.html.erb

1

Add a new part


2
3 <% form_for(@part, @make, @model) do |f| %>
4 <%= f.error_messages %>
5
6


7 <%= f.label :title %>

8 <%= f.text_field :title %>
9


10

11
12 <%= render :partial => ‘categories/form’,
13 :locals => {:category => @categories} %>
14
15
16

17
18


19 <%= observe_field :part_category_id,
20 :url => { :action => :get_subcategories },
21 :update => :subcategory_div,
22 :with => “‘category=’ + value”
23 %>
24

app/views/parts/new.html.erb

1

Editing part


2
3 <% form_for(@part) do |f| %>
4 <%= f.error_messages %>
5
6


7 <%= f.label :title %>

8 <%= f.text_field :title %>
9


10
11
12 <%= render :partial => ‘categories/form’,
13 :locals => {:category => @categories} %>
14
15
16

17
18


19 <%= observe_field :part_category_id,
20 :url => { :action => :get_subcategories },
21 :update => :subcategory_div,
22 :with => “‘category=’ + value”
23 %>
24


25
26


27 <%= f.submit ‘Update’ %>
28


29 <% end %>

app/views/categories/_form.html.erb

1 <%= label :part, ‘category_id’, ‘Category’ %>

2 <%= collection_select(
3 :part,
4 ‘category_id’,
5 @categories,
6 :id,
7 “name”,
8 {:include_blank => true}
9 )
10 %>

Any ideas?

What I have referenced:

http://shiningthrough.co.uk/blog/show/6
http://www.kahfei.com/?p=23

and by the way, the parts controller looks the following:

def new
@part = Part.new
@categories = Category.all

respond_to do |format|
  format.html # new.html.erb
  format.xml  { render :xml => @part }
end

end

GET /parts/1/edit

def edit
@part = Part.find(params[:id])
@categories = @part.category

respond_to do |format|
  format.html # edit.html.erb
  format.xml  { render :xml => @part }
end

end

You don’t show your Part model, but I suspect that it looks something
like:

class Part < ActiveRecord::Base
belongs_to :category
end

This allows you to do something like:

@part = Part.find(params[:id])
@category = @part.category

Note the subtle difference between what I wrote and what you wrote in
your edit view: (@category vs @categories)

A part belongs to a single category. When you reference
@part.category, you get that single category – the category to which
the part belongs. In particular, you don’t get a list of categories.
Since you don’t have a list of categories, you don’t have a
“collection” to which you can pass to #collection_select.

If you want to be able to use the Edit view to change the category to
which a part belongs, then you should probably do the same thing you
did in the action for your New view and do:

@categories = Category.all

–wpd

2009/10/20 ct9a [email protected]:

   format.xml  { render :xml => @part }
  end
 end

 # GET /parts/1/edit
 def edit
  @part = Part.find(params[:id])
  @categories = @part.category

That makes @categories only be a single category, which I think may be
the cause of the problem.

Colin

aha! fixed it.

  1. Removed usage of @categories in the collection_select call in the
    parts/new and edit views. Replaced it with ‘Category.all’
  2. Removed population of @categories by means of Categories.all in
    the parts controller.
  3. Removed putting in of ‘local’ hashref of :categories => @categories
    in the category/form partial (
    app/views/categories/_form.html.erb ).

ah, yes, as in doing so in new & edit methods in the Parts controller?

A bit heavy-handed…

  1. Removed usage of @categories in the collection_select call in the
    parts/new and edit views. Replaced it with ‘Category.all’

Now those new and edit views will always show all categories…
determining WHAT will be shown isn’t usually the purview of the view.

  1. Removed population of @categories by means of Categories.all in
    the parts controller.

But sometimes the controller determines what should be shown… it may
be nice to have one hunk of view code that can deal with different
conditions, i.e., maybe some categories, but not all… adopt that whole
Model-View-Controller thing.

  1. Removed putting in of ‘local’ hashref of :categories => @categories
    in the category/form partial (
    app/views/categories/_form.html.erb ).

That’s just plumbing dependent on where the categories are sourced…

The simpler solution was just to instantiate @categories similarly for
both the new and edit methods.