views:

32

answers:

2

Sorry if this question seems simple, I am very very new to Rails (just started learning a few days ago), but after consulting Google and "Agile Web Development with Rails" I can't find the answer.

I have an issue with Rails 2.3.8 creating a foreign key on two models. My tables look like this:

cars                                 manufacturer
----                                 ------------
car_make                             name
car_model                            country
car_class                            logo_url
image_url                            (and default 'id' created by Rails)
manufacturer_id
(and default 'id' created by Rails)

My 'car_make' and 'name' fields are essentially the same; every Car I create, I want to be able to associate it with an existing Manufacturer. This is the column I am trying to create FK on.

My car.rb has 'belongs_to :manufacturer', and my manufacturer.rb has 'has_many :cars' to establish a one manufacturer to many cars relationship. However, when I create a new car (via scaffolding) the manufacturer_id field is blank.

I went to my cars_controller, found the 'create' method that is being used, and tried to add the second line below:

@car = Car.new(params[:car])
@car.manufacturer_id = car.manufacturer.id  # <===

This produces a 'NameError in CarsController#create' error, and I see:

undefined local variable or method 'car' for #<CarsController:0x1034642f0>

Rails doesn't seem to like the line I've added. What am I missing to make this work?

A: 

Well, you need to have a manufacturer available before you can attach it to the car.

@car = Car.new( params[:car] )
m = Manufacturer.first # => as you can see you must already have one made
@car.manufacturer = m
@car.save

The reason car is undefined is because, well, you haven't defined it. Which car's manufacturer did you want to assign to @car?

So basically you need to make a manufacturer before you make a car. If the form you're filling out has the data for the manufacturer then make sure to put that under a different key in params, like, say, params[:manufacturer] and do a similar thing as you're doing with the car. Maybe like:

@car = Car.new( params[:car] )
@manufacturer = Manufacturer.find_or_create_by_name_and_country( params[:manufacturer][:name], params[:manufacturer][:country] )
@car.manufacturer = @manufacturer
@car.save
thenduks
Ah that makes sense. I want to find the correct manufacturer_id that corresponds to the car_make field. So for example, if my Manufacturer table is populated with 'Acura', 'Honda', and 'Toyota' under the names column, and I create a new car with car_make 'Honda', I want to find the correct manufacturer_id that is in the 'Honda' row.
Anon
Ah ha, so you should _not do that_. Car make should be found via `car.manufacturer.name`, not duplicated on the car itself!
thenduks
In order to hack it so it works (*bad idea*) you might try: `@car.manufacturer = Manufacturer.find_by_name(@car.car_make); @car.save` which will attempt to find the manuf by the car_make field of the car you just updated... Again, gonna have a bad time if you go too far down this path :)
thenduks
A: 

In your view, you want to generate a drop-down list for manufacturers (I would assume), so you should do something like this in the form:

<%= collection_select(:car, :manufacturer_id, Manufacturer.all, :id, :name) %>

Then your create action shouldn't need to explicitly set a manufacturer_id because it should have received that from the form.

Scott Anderson
Wow this design is a lot more intuitive, wonder why I didn't think of it before :P
Anon