has_many and belong_to association not working

I have two models. call.rb which has_many :visits and visit.rb which belongs_to :call. After populating call from the form which then shows all the parameters including the call.id I then make a visit corresponding to the call. the form for the new visit creates a new record ok and shows the input information except for I have it show me the call_id which is the foreign key and it tells me that it is nill when I look at the record in the ruby console. So it never associates the visit with the corresponding call. my call.rb is as follows

class Call < ActiveRecord::Base     ALL_FIELDS = %w(name address age area sex notes)     VALID_SEX = ["Male", "Female"]     validates_presence_of :name, :address, :age, :area     validates_inclusion_of :sex,                             :in => VALID_SEX,                             :message => "must be male or female"     has_many :visits, :foreign_key => 'call_id'

end the visit.rb is as follows

class Visit < ActiveRecord::Base     belongs_to :call, :class_name => 'Call', :foreign_key => 'call_id' end

my CallsController is

class CallsController < ApplicationController

  def index     @call = Call.find(:first, :order => 'RANDOM()')   end

  def new     @call = Call.new   end

  def create     @call = Call.new(params[:call])     if @call.save       flash[:notice] = "Call submission succeded"       render :action => 'show'     else       render :action => 'new'     end   end

  def show     @call = Call.find(params[:id])   end end

My visits controller is

class VisitsController < ApplicationController

  def index   end

  def show     @visit = Visit.find(params[:id])   end

  def new     @visit = Visit.new   end

  def create     @visit = Visit.new(params[:visit])     if @visit.save       flash[:notice] = "Visit submission succeded"       render :action => 'show'     else       render :action => 'new'     end   end

end And my schema after migrations is ActiveRecord::Schema.define(:version => 6) do

  create_table "calls", :force => true do |t|     t.string "name"     t.string "address"     t.string "age"     t.string "area"     t.date "date"     t.datetime "created_at"     t.datetime "updated_at"     t.string "sex", :default => "Male"     t.text "notes"   end

  create_table "visits", :force => true do |t|     t.integer "call_id"     t.datetime "created_at"     t.datetime "updated_at"     t.string "name"     t.string "address"     t.date "date"     t.string "placement"     t.string "time_of_day"     t.text "topic"     t.text "next_topic"   end

end

Any help for a noob will be much greatly appreciated

"I think make a visit corresponding to the call" is a little nebulous. How are you doing that?

Thanks for your reply

What is happening is that I create a call with a form from my new action in my ViewsController and enter information such as name and address. Then I execute the show action to view the entered data. The show view then has a button which I click to create a visit for that call (each call has_many visits). The show view for the call controller does show also the call.id so I know it exists. Then when the New action for the VisitsController is executed a new- visit form is opened in which I enter information for the visit that belongs_to that call. I enter information such as placement, topic etc. then I execute the show action for the VisitsController and it displays the information and the flash notice showing that the visit was sucessfully created. I try to also display call_id which is the foreign key for the visit but it displays nothing and when I check the values for the visit record in the ruby console it tells me that the value for call_id is nil. I hope this explains it better. This is my first rails project so any help would be greatly appreciated.

Help please - does anyone have any other ideas on why I can't get this association to work?

Can you get the associations to work at the console?

FWIW--that foriegn_key arg on the has_many looks weird to me--it's the child tables that get FKs, not the parent. And at any rate, you're following the rails conventions there, so you shouldn't have to specify those explicitly (ditto on the :class_name arg).

Thanks for the reply

In fact I changed the models back to

class Call < ActiveRecord::Base     has_many :visits     ALL_FIELDS = %w(name address age area sex notes)     VALID_SEX = ["Male", "Female"]     validates_presence_of :name, :address, :age, :area     validates_inclusion_of :sex,                             :in => VALID_SEX,                             :message => "must be male or female"

end

And

class Visit < ActiveRecord::Base     belongs_to :call end

But the association does not work in the console When I create a new visit from the show action link in my calls.view.show.rhtml to new visit I go to the form for the new visit and populate it with values. I try to display the call_id and get nothing though it displays my other entered fieds. Then when I go to the ruby console to check the values of the new visit record the value of the foreign key call_id is nil. So I am not sure why this is so. When I do the show page from the call views I display the call.id for the call and it has the proper id but it never gets over to the call_id column in the new visit I make. The association doesn't get the call_id. I am sorry I,m such a noob but this is my first rails app I have all the books and have done a few screecasts but am stuck here Thanks for your help

Well--let's leave the views out of the picture for a sec. Can you do something like:

my_call = Call.find(:first) my_call.visits.count # <- we want one w/a count of 0 my_visit = Visit.find(:first) my_call.visits < my_visit my_call.save my_call.visits.count # <- does this return '1'? my_call.id == my_visit.call_id # <- do we get a 'true' here?

If that works, I think you can say your association is in fact working, and we can start dissecting your views.

Dang it--that third line there should be

Hello thanks again Here is what I get (I used the Visit with an id of 3 as the first couple had no data)

my_call.visits < my_visit

TypeError: compared with non class/module   from /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/ associations/association_collection.rb:164:in `<'   from /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/ associations/association_collection.rb:164:in `send'   from /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/ associations/association_collection.rb:164:in `method_missing'   from /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/ base.rb:1693:in `with_scope'   from /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/ associations/association_collection.rb:164:in `send'   from /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/ associations/association_collection.rb:164:in `method_missing'   from (irb):10

So this is where I guess it falls apart Thanks again Roy

LOL--more of my typos--sorry.

Make that

  my_call.visits << my_visit

please.

Thanks Roy - Yes I do get a true after my_call.id==my_visit.call_id

Okay then--cool. And if I follow the earlier stuff, the view-mediated Visit create process is not in question, right? It's just the bit where you create a Call from off a visits/show view? The resulting call does not have the proper Visit reference? (And have you confirmed this by looking in your db?)

If that's all right--how are you kicking off the process of creating a new Call from your visits/show view? I'm guessing a link_to call? Let's see that to start please.

Thanks again for the reply

Actually its the other way around each call has many visits and each visit belongs to one call. I create the call first and populate the form and it then shows me in the ruby console that all the fields are populated (the call.id, call.name, call.address, etc) Then what I try to do is create a new visit form that call (it has further info and later I want to create new visits for that call)

On each calls.show.rhtml page I show some of what I entered and there is link to create a new visit for that call that links to the new action of the visits controller. This is where I want the association to take place. It should take the call.id from the call and make it the visits.call_id for that visit.

here is the views.calls.show.rhtml code

<h2><%= @call.name %></h2> <p><%= @call.address %></p> <p><%= @call.area %></p> <p><%= @call.date %></p> <p><%=@call.id %></><br /> <%= link_to 'New Visit', :controller => "visits", :action => "new", :call_id => @call.id %> <p><%= debug(params) %></p>

which opens a form for a New Visit

And here is the views.visits.new.rhtml

<%= error_messages_for 'visit' %> <% form_for @visit do |f| %>

<p>     date:<br />     <%= date_select ("post", "date") %> </p>

<p>     placement:<br />     <%= f.text_field :placement %> </p> <p>     time of day:<br />     <%= f.text_field :time_of_day %> </p> <p>     topic:<br />     <%= f.text_field :topic %> </p> <p>     next topic:<br />     <%= f.text_field :next_topic%> </p>

<p>     <%= f.submit "Create" %> </p> <p> <%= debug(params) %> </p>

<% end %>

When I check in the ruby console It show the record having been populated except fot the visit.call_id which it records as nil. So it is not getting the call.id from the call

Thanks again so much for your help

Ah, okay then. So this

  <%= link_to 'New Visit',               :controller => "visits",               :action => "new",               :call_id => @call.id %>

Should bring us over to VisitsController.new(). I would expect that code to look something like:

  def new     @visit = Visit.new     @visit.call_id = params[:call_id] # <- is something like this line here?     respond_to do |format|       format.html # new.html.erb       format.xml { render :xml => @project }     end   end

How close is that?

Thank you again Roy. Actually Roy my whole visits controller is

class VisitsController < ApplicationController

  def index   end

  def show     @visit = Visit.find(params[:id])   end

  def new     @visit = Visit.new   end

  def create     @visit = Visit.new(params[:visit])     if @visit.save       flash[:notice] = "Visit submission succeded"       render :action => 'show'     else       render :action => 'new'     end   end

end

So this is most likely where I am having trouble

I think you're right. Your link_to call is passing the id of the current call to your visit controller in a parameter called :call_id. You can retrieve it out of the params hash in the same way that your show method pulls :id out. But right now you're not doing that. Try adding this line under your @vist = Visit.new call:

  @visit.call_id = params[:call_id]

Any better?

Cheers,

-Roy

I'm sorry Roy I am not sure where to put that line - after @visit = Visit.new in the new action of the VisitsController or do I replace the new action with what you had above

def new     @visit = Visit.new     @visit.call_id = params[:call_id] # <- is something like this line here?     respond_to do |format|       format.html # new.html.erb       format.xml { render :xml => @project }     end   end

Thanks again

Thanks again Roy. After I put it in the new action it looked like this and i left off the xml stuff but it still didn't pass the call.id to the call_id field in the visit. I can't figure out why - maybe its the link_to 'New Visit ' line in my show view in my calls.views I don't know.

  def new     @visit = Visit.new     @visit.call_id = params[:call_id]   end

Hmmm--so either we're not getting a value in params[:call_id] or it's not making it into the visits/new form. Probably the former.

I'm sure there's a better way to echo the contents of params to the browser from a controller action (little help anyone?) but for now, can you make this the first line in VisitsController.new:

  raise(debug(params))

And let's see what's in that params hash...

Hello Roy

I got an NoMethodsError in VisitsController#New and undefined method 'debug' for for #<VisitsController:0x19b90c8>

What I put was

class VisitsController < ApplicationController

  def index   end

  def show     @visit = Visit.find(params[:id])   end

  def new     raise(debug(params))     @visit = Visit.new     #@visit.call_id = params[:call_id]   end

  def create     @visit = Visit.new(params[:visit])     if @visit.save       flash[:notice] = "Visit submission succeded"       render :action => 'show'     else       render :action => 'new'     end   end

end

And then at the bottom of all the errot stuff I got So I'm not sure if this is what you want but it does say call_id is 43 which is correct.

Request

Parameters:

{"call_id"=>"43"}

Show session dump