How to populate a table with id of selected item from another table

Hi,

I have a "New Expense" form that includes a select field named vendor
that provides a a drop-down list of all vendors.

When a user makes a selection of a vendor-name, that name populates
the vendor field of the new Expense record. I'm happy with the drop-
down list of names, but I'd rather populate the Expense record with
the ID of the vendor.

IMHO, this is a common database problem. Can you point me to a
simple example on the Web for handling this. I've found plenty of
HABTM examples with check-boxes, but none (so far) exactly on point.

Thanks in Advance,
Richard

OK, so populate the option values with the ID. This is basic HTML.

RichardOnRails wrote:

Hi,

I have a "New Expense" form that includes a select field named vendor
that provides a a drop-down list of all vendors.

When a user makes a selection of a vendor-name, that name populates
the vendor field of the new Expense record. I'm happy with the drop-
down list of names, but I'd rather populate the Expense record with
the ID of the vendor.

IMHO, this is a common database problem. Can you point me to a
simple example on the Web for handling this. I've found plenty of
HABTM examples with check-boxes, but none (so far) exactly on point.

Just use collection_select or something. What exactly are you having
trouble with?

Thanks for your responses, Hassan and Marnen.

This is what I had, which returned vendors' names and parenthesized
nicknames:

    <% def parens(s); s.empty? ? "" : " (#{s})"; end -%>
    <% @current_vendors =
Vendor.find(:all, :order=>"nickname").collect { |v|
      v.nickname + parens(v.qbname) } %>
    <%= f.select :vendor, @current_vendors %>

In response, to Hassan's suggestion, I used the following which (as I
expected) presented merely ids and no names which a user could use to
identify the desired vendor:

    <% @current_vendors =
Vendor.find(:all, :order=>"nickname").collect { |v|
      v.id } %>
    <%= f.select :vendor, @current_vendors %>

What I want is to have vendor-names to be displayed in the drop-down
and the selected name to be displayed in the form but, upon
submission, have the selected vendor's ID stored in the database
rather than the selected name.

Best wishes,
Richard

If you (hint, hint) look at the API doc for `select`, you'll see an example
of *exactly* the result you're trying to achieve.

Hassan Schroeder wrote:

Okay, guys: I can take a hint :slight_smile: Finally I did a Google search based
on your hit that got me what I was heretofore unable to find: "rails
api select"

I don't have time today to code and test this, so I'll just post my
ideas here to see if they sound sensible to you guys.

In my "New Expense" form:
    <%= f.collection_select(:vendor, :vendor_id, Vendor.all, :id,
name_w_nickname -%>

In my Expense class:
    belongs_to :vendor

In my Vendor class:
    has_many :expenses
and
    def name_w_nickname
        %<%s (%s)> % [name, nickname]
    end

I need to do something about possible nil in the nickname field,
maybe: nickname ||= "".

If you guys are up to it, I'd appreciate any observations you may
care to offer.

Best wishes,
Richard

Okay, guys: I can take a hint :slight_smile: Finally I did a Google search based
on your hit that got me what I was heretofore unable to find: "rails
api select"

Wow. You've been doing Rails development without using the
API docs? Kinda like playing tennis in the dark. in handcuffs. :slight_smile:

In my "New Expense" form:
<%= f.collection_select(:vendor, :vendor_id, Vendor.all, :id,
name_w_nickname -%>

As already mentioned -- don't do DB access in the view. Move that
Vendor.all to your controller and use it to set a var, e.g. @vendors.

Aside from theoretical considerations, it means you don't have to
change any views when you have a business need to replace the
`Vendor.all` with, say, a named scope like `Vendor.approved`.

FWIW,

Hi Hissan,

Thanks for your response.

Wow. You've been doing Rails development without using the
API docs? Kinda like playing tennis in the dark. in handcuffs. :slight_smile:

Well, I wasn't completely without resources, e.g. the links (now
expanded, thanks to you) I maintain under one Firefox tab:
<a href="http://www.ruby-doc.org/core/">Ruby-Doc.org/core</a></p>
<a href="http://stdlib.rubyonrails.org/">Ruby Standard Library
Documentation</a></p>
<a href="http://www.zenspider.com/Languages/Ruby/QuickRef.html">Ruby/
QuickRef.html</a></p>
<a href="http://guides.rubyonrails.org/migrations.html">RubyOnRails
Guide: Migrations</a></p>
<a href="http://www.williambharding.com/blog/rails/rails-scriptserver-
command-line-options">rails-scriptserver-command-line-options</a></p>
<a href="http://guides.rubyonrails.org/command_line.html">RubyOnRails
Guide: command_line</a></p>
<a href="http://dizzy.co.uk/ruby_on_rails/cheatsheets/rails-
migrations">RubyOnRails Migrations CheatSheet</a></p>
<a href="http://api.rubyonrails.org/classes/ActionView/Helpers/
FormOptionsHelper.html">RubyOnRails: FormOptionsHelper</a></p>

and my Rails library:
The Rails Way
Rails Cookbook
Practical Prototype & Script.aculo.us
Rails Recipes
Advanced Rails Recipes
Practical REST on Rails 2 Projects
... and quite a few more

That was the fun part. Here's the serious question:

1. When I bring up my app and click the link for "New Expense", I see
"http://localhost:3000/expenses/new" in Firefox' Address bar and I get
the following 10 lines or so:

NameError in Expenses#new

Showing app/views/expenses/new.html.erb where line #10 raised:

undefined local variable or method `nickname' for #<ActionView::Base:
0x442c8f0>

Extracted source (around line #10):

7:
8: <p>
9: <%= f.label :vendor %><br />
10: <%= f.collection_select(:vendor, :vendor_id, @vendors, :id,
nickname) -%>
11: <%= link_to 'New
Vendor', :controller=>'vendors', :action=>'new' %>
12: </p>
13: <p>

2. I think "nickname" is a legitimate method for Vendor. For example,
if I load Firefox' Address bar with "http://localhost:3000/vendors", I
get:

Listing vendors
Home Vendor Expense
Nickname QB_name
001v One Show Edit Destroy
002v Two Show Edit Destroy
003nick 003qb Show Edit Destroy
[snip]

3. I tried a colon in front of "nickname" in the f.collection_select
statement to no avail; besides, the documentation you referred to
suggested a bareword.

4. Any ideas?

Thanks in Advance,
Richard

? I'm looking at (unframed)

<http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#M002303>
with this 'sample usage':

  collection_select(:post, :author_id, Author.all, :id,
:name_with_initial, {:prompt => true})

Are you sure you got the *exact same* error using :nickname ?

If so, what's the code that creates @vendors ?

Hi Hassan,

Thanks for your continued consideration of my problem. I hope some of
the following is helpful, though it seems like way to much
information.

? I'm looking at (unframed)

<http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelp…>
with this 'sample usage':

  collection_select(:post, :author_id, Author.all, :id,
:name_with_initial, {:prompt => true})

Here’s the section of of the doc I looked at:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#M002303,
which seems to match the portion you cited.

Are you sure you got the *exact same* error using :nickname ?

Since this section referenced a method that returned a string, I took
a short-cut to simply name an object whose value was a string. But in
case that’s the cause of the problem, I changed my app to closely
follow the example in the doc.

If so, what's the code that creates @vendors ?

Good question: I DON’T KNOW! I see a several methods in app
\controllers\vendors_controller.rb the populate @vendors with
Vendor.all.
Maybe the absence of an assignment to @vendors is what’s wrong, but I
don’t know what to do about it/

Carrying on in case the changes I made are useful, I note that this
section shows the command format as follows:

collection_select(object, method, collection, value_method,
text_method, options = {}, html_options = {})

It shows the object structure to be used with this method:
  class Post < ActiveRecord::Base
    belongs_to :author
  end
  class Author < ActiveRecord::Base
    has_many :posts
    def name_with_initial
      "#{first_name.first}. #{last_name}"
    end
  end

I’ve got: app\models\expense.rb:
    class Expense < ActiveRecord::Base
        belongs_to :vendor
    end

and app\models\vendor.rb:
    class Vendor < ActiveRecord::Base
      has_many :expenses

      def name
          #{nickname}
    end

I’ve got a *revised* app\views\expenses\new.html.erb, lines 8-12 in
order to follow the example more exactly:
  <p>
    <%= f.label :vendor %><br />
    <%= f.collection_select(:vendor, :vendor_id,
@vendors, :id, :name) -%>
    <%= link_to 'New
Vendor', :controller=>'vendors', :action=>'new' %>
  </p>

When I run the app and click on the New Expense link, I get a
*revised* symptom, which is the error page below starting with
**NoMethodError in Expenses#new** in 24-point font.

I can post all the app’s code or any partion thereof in a zip file if
that would be helpful to you.

Thank you for helping me to get this functionality going.

Best wishes,
Richard

NoMethodError in Expenses#new
Showing app/views/expenses/new.html.erb where line #10 raised:
undefined method `merge' for :name:Symbol
Extracted source (around line #10):
7:
8: <p>
9: <%= f.label :vendor %><br />
10: <%= f.collection_select(:vendor, :vendor_id,
@vendors, :id, :name) -%>
11: <%= link_to 'New
Vendor', :controller=>'vendors', :action=>'new' %>
12: </p>
13: <p>
RAILS_ROOT: K:/_Projects/Ruby/_Rails_Apps/_EIMS/RTS
Application Trace | Framework Trace | Full Trace
K:/_Utilities/ruby186-26_rc2/ruby/lib/ruby/gems/1.8/gems/
actionpack-2.3.5/lib/action_view/helpers/form_helper.rb:1025:in
`objectify_options'
K:/_Utilities/ruby186-26_rc2/ruby/lib/ruby/gems/1.8/gems/
actionpack-2.3.5/lib/action_view/helpers/form_options_helper.rb:588:in
`collection_select'
K:/_Projects/Ruby/_Rails_Apps/_EIMS/RTS/app/views/expenses/
new.html.erb:10:in `_run_erb_app47views47expenses47new46html46erb'
K:/_Projects/Ruby/_Rails_Apps/_EIMS/RTS/app/views/expenses/
new.html.erb:5:in `_run_erb_app47views47expenses47new46html46erb'
K:/_Projects/Ruby/_Rails_Apps/_EIMS/RTS/app/controllers/
expenses_controller.rb:30:in `new'
Request
Parameters:
None
Show session dump
Response
Headers:
{"Content-Type"=>"text/html",
"Cache-Control"=>"no-cache"}

Hassan,

Please hold off on looking at my last, unreasonably large post. I'm
embarrassed to have posted such a monstrosity.

I found a bunch of tutorials on collection_select, so I should be
able to discover where I've gone astray in trying to apply that method
in my app. I'll post back how I solved my problem using those
resources, should I be so fortunate.

Best wishes,
Richard