Getting started with Ruby on Rails and Relationships

Hello! I’m relatively new to Ruby on Rails, but decided to start
experimenting with it after looking at how it can simply some rather
repetitive tasks that I find myself writing with PHP. For the most part,
I’ve been learning through books and writing code, as expected, and tend
to plug away at something until I can get it right. Working with
relationships, however, has proven a bit difficult so I thought I would
try to solicit some help from anyone willing…

As part of this experiment, I’m building a sample bookstore that has two
database tables (author, book). Author is setup as has_many :book, and
book as has_one :author

Authors simply has id, firstname, lastname fields while book stores id,
title, description, author_id

Inside the book controller, it calls a simple find to display all books
by a particular author

@results = Book.find(:all, :conditions => { :author_id => entry.id})

Entry.id is a numeric value provided by a form on a previous page.

The view page itself is:

<% @results.each do |result| %>
<%= h(book.title)%>
<%= h(book.description)%>
<% end %>

All of this works fine.

The question is: Given the setup, how do I display the appropriate first
and last name of the author for each book? I’ve tried a variety of
different approaches to no avail, and I’m guessing its just a minor
error in my methodology.

Hi,

As a side-note, instead of doing
@results = Book.find(:all, :conditions => { :author_id => entry.id})

You can do this:
@results = Author.find(entry.id).books

Or if entry is already an author instance
@results = entry.books

This also infers that your relations ships are:
has_many :books and belongs_to :author

On to your actual question, you would want to do:

<% @results.each do |result| %>
<%= h(book.title) %>
<%= h(book.description) %>
<%= h(book.author.firstname) %>
<%= h(book.author.lastname) %>
<% end %>

If this gives you problems, check that your relationships are like I
said
above:
has_many :books on the author model
belongs_to :author on the book model

Hope this helps.

Cheers,
James

If you have a has_many/belongs_to relationship between authors and
books, finding one should give you access to the other.

For example, if author has_many books, you should be able to do this:

a = Author.find(entry.id) # returns author object with id == entry.id
@results = a.books # collections of books by the author

Then you should be able to access a.firs_name and a.last_name (or
whatever).

The Rails console is your friend. In a terminal, cd to the root of your
app, then enter “script/console” (or “ruby script/console”). You can
enter the lines above (with real numbers, of course) and see the author
object, and then see if an array of books is returned (assuming you have
relationships).

Neil H. wrote:

Hello! I’m relatively new to Ruby on Rails, but decided to start
experimenting with it after looking at how it can simply some rather
repetitive tasks that I find myself writing with PHP. For the most part,
I’ve been learning through books and writing code, as expected, and tend
to plug away at something until I can get it right. Working with
relationships, however, has proven a bit difficult so I thought I would
try to solicit some help from anyone willing…

As part of this experiment, I’m building a sample bookstore that has two
database tables (author, book). Author is setup as has_many :book, and
book as has_one :author

Authors simply has id, firstname, lastname fields while book stores id,
title, description, author_id

Inside the book controller, it calls a simple find to display all books
by a particular author

@results = Book.find(:all, :conditions => { :author_id => entry.id})

Entry.id is a numeric value provided by a form on a previous page.

The view page itself is:

<% @results.each do |result| %>
<%= h(book.title)%>
<%= h(book.description)%>
<% end %>

All of this works fine.

The question is: Given the setup, how do I display the appropriate first
and last name of the author for each book? I’ve tried a variety of
different approaches to no avail, and I’m guessing its just a minor
error in my methodology.

Thank you!

Just one follow-up…

On your recommendation for using
@results = Author.find(entry.id).books instead of my longer Find query,
how would you appropriately adjust it if we expanded to check multiple
fields. Say we created a new field, status.

Would @results = Author.find(entry.id, status).books be appropriate?

James Brooks wrote:

Hi,

As a side-note, instead of doing
@results = Book.find(:all, :conditions => { :author_id => entry.id})

You can do this:
@results = Author.find(entry.id).books

Or if entry is already an author instance
@results = entry.books

This also infers that your relations ships are:
has_many :books and belongs_to :author

On to your actual question, you would want to do:

<% @results.each do |result| %>
<%= h(book.title) %>
<%= h(book.description) %>
<%= h(book.author.firstname) %>
<%= h(book.author.lastname) %>
<% end %>

If this gives you problems, check that your relationships are like I
said
above:
has_many :books on the author model
belongs_to :author on the book model

Hope this helps.

Cheers,
James

Rails has some magic finders.

To find based on one attribute, like lastName, use
Author.find_by_lastName(‘wibble’)
To find on two attributes, like lastName and status, use
Author.find_by_lastName_and_status(‘wibble’, ‘dead’)

These finders only return one record (the first one they find in the db,
which may not be the one you expect). To find all records that match the
criteria, use instead Author. find_all_by…

Finding by a record’s id is a special case, which is the one I
originally presented: Author.find(id), so your construction will not
work.

If you need to search on more fields (like lastName, firstName, and
status) you’ll have to use find(:all) with modifiers. That’s a bit much
to go into here, but is well covered in the Agile Web D. book.
To give you an idea, a query could be written as

Author.find(:all, :conditions => “lastName = ‘wibble’ and status =
‘dead’”)

BTW, if you are pulling the values for comparison (i.e., ‘wibble’ and
‘dead’ in my example) from form fields, make sure you understand SQL
Injection before you do anything like the above query.

http://www.google.com/search?q=rails+sql+injection

Neil H. wrote:

Thank you!

Just one follow-up…

On your recommendation for using
@results = Author.find(entry.id).books instead of my longer Find query,
how would you appropriately adjust it if we expanded to check multiple
fields. Say we created a new field, status.

Would @results = Author.find(entry.id, status).books be appropriate?