Forum: Ruby on Rails Modelling Foreign Keys

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Arch S. (Guest)
on 2006-04-01 02:22
Can someone point me to a reference or tutorial that shows how to map
foreign key relationships in the model?

For example given:

Users
 id
 name
 email

Posts
 id
 user_id
 title

How do I associate user_id with users.id in the Post and User models?
has_many and belongs_to don't seem to do it.
Andre (Guest)
on 2006-04-01 03:36
Arch S. wrote:
> Can someone point me to a reference or tutorial that shows how to map
> foreign key relationships in the model?
>
> For example given:
>
> Users
>  id
>  name
>  email
>
> Posts
>  id
>  user_id
>  title
>
> How do I associate user_id with users.id in the Post and User models?
> has_many and belongs_to don't seem to do it.


This cheatsheet might be helpful:

http://slash7.com/cheats/activerecord_cheatsheet.pdf

Regards,
Andre
Steve K. (Guest)
on 2006-04-01 04:18
In this case, why won't it?

In your user model, you'd say

  has_many :posts

and in the post model you'd say

  belongs_to :user

and that's all you need for what you describe. What's not working?

Arch S. wrote:
> Can someone point me to a reference or tutorial that shows how to map
> foreign key relationships in the model?
>
> For example given:
>
> Users
>  id
>  name
>  email
>
> Posts
>  id
>  user_id
>  title
>
> How do I associate user_id with users.id in the Post and User models?
> has_many and belongs_to don't seem to do it.
Arch S. (Guest)
on 2006-04-01 05:25
Steve K. wrote:
> In this case, why won't it?
>
> In your user model, you'd say
>
>   has_many :posts
>
> and in the post model you'd say
>
>   belongs_to :user
>
> and that's all you need for what you describe. What's not working?
>


Well in the view I get no visibility to the foreign keys.  Just now I
found this  example:

class Student < ActiveRecord::Base
  set_table_name "students"
  set_primary_key "id"

  belongs_to :advisor, :class_name=>"Advisor", :foreign_key =>
"advisor_id"
  belongs_to :second_advisor, :class_name=>"Advisor", :foreign_key =>
"sub_advisor"

  has_and_belongs_to_many :courses, :class_name=>"Course"

end

I want my posts/edit to allow me to select a user.
Arch S. (Guest)
on 2006-04-01 05:38
So that cheat sheet raised some questions.  First it sounds like it is
saying not to use has_many and belongs_to with foreign keys??

I guess what I want an example of is how to set my simple example up so
that in the basica scaffold view I can edit/select the values for a
property that is a foreign key.  So from the post view I want to
select/assign the user.
Chris H. (Guest)
on 2006-04-01 05:56
(Received via mailing list)
models:

class User < ActiveRecord::Base
  has_many :posts
end

class Post < ActiveRecord::Base
  beongs_to :user #
end

controller

class PostController < ApplicationController
  def new
    @post = Post.new
    @users = User.find(:all)
  end
end

view (new.rhtml)

<%= start_form_tag :action => "create" %>
...
<%= select :post, :user_id, options_from_collection_for_select(@users,
"id",
"name") %>
...
<%= end_form_tag %>
Arch S. (Guest)
on 2006-04-01 06:12
Chris H. wrote:
> models:
>
> class User < ActiveRecord::Base
>   has_many :posts
> end
>
> class Post < ActiveRecord::Base
>   beongs_to :user #
> end
>


Thanks Chris.

So, what do I get from explicitly identifying the foreign key
relationship in the model (like belongs_to :advisor,
:class_name=>"Advisor", :foreign_key =>
"advisor_id")??

Thanks.
Chris H. (Guest)
on 2006-04-01 06:54
(Received via mailing list)
you're not getting anything.  Rails figures out that info based on the
criteria you specify.  if you stick to Rails conventions, you don't have
to
do anything but provide the association name, rails does the rest.

so in that example

student belongs_to :advisor

rails will make the following assumptions:

students table contains an "advisor_id" column that references the id
column
in advisors table
the associated class is named "Advisor"

example 2:

student belongs_to :advisor, :class_name => "Person"

in this case, we must tell the model to not make the default
assumptions,
since our association name has nothing to do with what we really want.
you
have to be explicit if you don't want to stick to Rails conventions
Arch S. (Guest)
on 2006-04-01 07:07
Chris H. wrote:
> you're not getting anything.  Rails figures out that info based on the
> criteria you specify.  if you stick to Rails conventions, you don't have
> to
> do anything but provide the association name, rails does the rest.
>


Thank you Chris that was extremely helpful.  It makes sense now.
Arch S. (Guest)
on 2006-04-01 07:41
Chris H. wrote:
> you're not getting anything.  Rails figures out that info based on the
> criteria you specify.  if you stick to Rails conventions, you don't have
> to
> do anything but provide the association name, rails does the rest.
>
> so in that example
>
> student belongs_to :advisor
>
> rails will make the following assumptions:
>
> students table contains an "advisor_id" column that references the id
> column
> in advisors table
> the associated class is named "Advisor"
>


I guess I do have a follow up question.

In the above example, what is gained by adding a has_many relationship
to Advisor?

advisor has_many :students
d6veteran (Guest)
on 2006-04-02 08:32
I'm really having a hard time implementing foreign keys and I find it
odd that Rails makes so many things easy, yet foreign keys don't seem to
be supported.  Maybe I am missing something.  Here's the revelant set up
info:

Table Test
  id
  title
  summary
  test_type_id
---------------------
Table Test_Type
  id
  type_name
---------------------
class Admin::TestController < Admin::BaseController
    scaffold :test
    def new
        @test = Test.new
        @test_type = TestType.find(:all)
    end
end
---------------------
class Admin::TestTypeController < Admin::BaseController
    scaffold :test_type

end
---------------------
class Test < ActiveRecord::Base
    has_many :questions
    has_many :logged_tests
    has_many :results
    belongs_to :test_type
    belongs_to :user
end
---------------------
class TestType < ActiveRecord::Base
    has_many :tests
end
---------------------
views/admin/test/new.rhtml

<html>
<body>

<%= start_form_tag :action => "create" %>
  <p>
    <label for="test_title">Title</label><br />
    <%= text_field_tag("test_title", nil, :size => "40") %></p>
  <p>
    <label for="test_summary">Summary</label><br />
    <%= text_area_tag("test_summary", nil, :size => "40x20") %>
  </p>
  <p>
    <%= select :test, :test_type,
options_from_collection_for_select(@test_types, "id", "type_name") %>
  </p>
  <p>
    <%= submit_tag(value = "Create New Test") %>
  </p>
<%= end_form_tag() %>

<a href="/admin/test/list">Back</a>
</body>
</html>
---------------------
error:

ActionView::TemplateError (undefined method `inject' for nil:NilClass)
on line #19 of app/views/admin/test/new.rhtml:
16:     <%= text_area_tag("test_summary", nil, :size => "40x20") %>
17:   </p>
18:   <p>
19:     <%= select :test, :test_type,
options_from_collection_for_select(@test_types, "id", "type_name") %>
20:   </p>
21:   <p>
22:     <%= submit_tag(value = "Create New Test") %>

    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_view/helpers/form_options_helper.rb:141:in
`options_from_collection_for_select'
    #{RAILS_ROOT}/app/views/admin/test/new.rhtml:19
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_view/base.rb:268:in
`send'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_view/base.rb:268:in
`compile_and_render_template'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_view/base.rb:244:in
`render_template'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_view/base.rb:205:in
`render_file'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:655:in
`render_file'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:595:in
`render_with_no_layout'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/layout.rb:228:in
`render_with_a_layout'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:684:in
`render_with_layout'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:645:in
`render_action'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/scaffolding.rb:153:in
`render_scaffold'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/scaffolding.rb:117:in
`new'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:853:in
`send'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:853:in
`perform_action_without_filters'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/filters.rb:332:in
`perform_action_without_benchmark'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/benchmarking.rb:69:in
`perform_action_without_rescue'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/benchmarking.rb:69:in
`measure'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/benchmarking.rb:69:in
`perform_action_without_rescue'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/rescue.rb:82:in
`perform_action'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:369:in
`send'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/base.rb:369:in
`process_without_session_management_support'
    /usr/lib/ruby/gems/1.8/gems/actionpack-1.11.2/lib/action_controller/session_management.rb:116:in
`process'
    /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/dispatcher.rb:38:in
`dispatch'
    /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/fcgi_handler.rb:141:in
`process_request'
    /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/fcgi_handler.rb:53:in
`process!'
    /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/fcgi_handler.rb:52:in
`each_cgi'
    /usr/lib/ruby/1.8/fcgi.rb:597:in `each'
    /usr/lib/ruby/1.8/fcgi.rb:597:in `each_cgi'
    /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/fcgi_handler.rb:52:in
`process!'
    /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/fcgi_handler.rb:22:in
`process!'
    dispatch.fcgi:33


Any help appreciated.
Ray B. (Guest)
on 2006-04-02 09:30
(Received via mailing list)
d6veteran wrote:
> I'm really having a hard time implementing foreign keys and I find it
> odd that Rails makes so many things easy, yet foreign keys don't seem to
> be supported.  Maybe I am missing something.  Here's the revelant set up
> info:

You could use the scaffolding to build a working example of the logic
here.

Your problem on line 19, is that you have a variable @test_types, which
you didn't define in your controller. The
options_from_collection_for_select calls inject on this nil object and
you get this error.

--

Ray
Arch S. (Guest)
on 2006-04-02 09:33
Ray B. wrote:
> d6veteran wrote:
>> I'm really having a hard time implementing foreign keys and I find it
>> odd that Rails makes so many things easy, yet foreign keys don't seem to
>> be supported.  Maybe I am missing something.  Here's the revelant set up
>> info:
>
> You could use the scaffolding to build a working example of the logic
> here.
>
> Your problem on line 19, is that you have a variable @test_types, which
> you didn't define in your controller. The
> options_from_collection_for_select calls inject on this nil object and
> you get this error.
>
> --
>
> Ray

I thought I was using the scaffolding.

So you mean in the TestTypeController I need to define @test_types?
Ray B. (Guest)
on 2006-04-02 10:25
(Received via mailing list)
Arch S. wrote:

> I thought I was using the scaffolding.

I was wrong about this. I thought that the scaffolding created the
correct scaffolding for the associations, but it doesn't.

> So you mean in the TestTypeController I need to define @test_types?

Yes. There won't be anything in the drop down until you create some
test_types though.


--

Ray
Arch S. (Guest)
on 2006-04-02 19:49
Ray B. wrote:
> Arch S. wrote:
>
>> So you mean in the TestTypeController I need to define @test_types?
>
> Yes. There won't be anything in the drop down until you create some
> test_types though.
>
>
> --
>
> Ray

That doesn't make any sense to me.  I look through the rest of my
controllers and I can access the entire model without anything more than
a scaffold declaration.

I understand that I should define test_type in my Type controller, as I
have done here:

class Admin::TestController < Admin::BaseController
    scaffold :test
    def new
        @test = Test.new
        @test_type = TestType.find(:all)
    end
end
---------------------
class Admin::TestTypeController < Admin::BaseController
    scaffold :test_type

end

Not sure why this is not working.
Ray B. (Guest)
on 2006-04-03 02:22
(Received via mailing list)
Arch S. wrote:

> Not sure why this is not working.

You are referencing @test_types in you view, not @test_type.

You are defining @test_type in your controller, not @test_types.

They need to be the same.
Steve K. (Guest)
on 2006-04-03 20:40
The point of telling Rails about the relationships between models is not
because Rails will magically create scaffolding for you but because
you'll be able to access you data through the relations.

For instance, once you've set up those two relationships in your models,
you can do things like

@advisor = Advisor.find(1)
@students = @advisor.students

and conversely, if you have a student selected into @student, you can
get the advisor's name simply via @student.advisor.name

Or if you're updating a student's attributes in a controller action, if
you set some of @student.advisor's attributes, the changes to the
advisor will also get saved when you simply call @student.save

and all sorts of stuff like that.

Arch S. wrote:
> Chris H. wrote:
.... snip ...
>> so in that example
>>
>> student belongs_to :advisor
>>
>> rails will make the following assumptions:
>>
>> students table contains an "advisor_id" column that references the id
>> column
>> in advisors table
>> the associated class is named "Advisor"
>>
>
>
> I guess I do have a follow up question.
>
> In the above example, what is gained by adding a has_many relationship
> to Advisor?
>
> advisor has_many :students
Arch S. (Guest)
on 2006-04-03 20:48
Steve K. wrote:
> The point of telling Rails about the relationships between models is not
> because Rails will magically create scaffolding for you but because
> you'll be able to access you data through the relations.
>
> For instance, once you've set up those two relationships in your models,
> you can do things like
>
> @advisor = Advisor.find(1)
> @students = @advisor.students
>
> and conversely, if you have a student selected into @student, you can
> get the advisor's name simply via @student.advisor.name
>
> Or if you're updating a student's attributes in a controller action, if
> you set some of @student.advisor's attributes, the changes to the
> advisor will also get saved when you simply call @student.save
>
> and all sorts of stuff like that.
>

Thanks for the reply.  I cleaned up my typos and tried calling
@test.test_type.id and it works.  That is cool.
Chris H. (Guest)
on 2006-04-03 21:00
(Received via mailing list)
associations are a two way street.

in the student advisors example

# student belongs_to :advisor
s = Student.find(1, :include => :advisor) # find student with id = 1
puts s.advisor.name # print name of the student's advisor

# advisor has_many :students
a = Advisor.find(1, :include => :students) # find advisor with id = 1
a.students.each { |s| puts s.name } # print all the names of the
students
for this advisor
This topic is locked and can not be replied to.