Search code examples
ruby-on-railsrubymodelshas-manybelongs-to

Ruby on Rails: Display relationship between 2 models


I have an authors page that displays all the authors in the database.

<h1>Listing authors</h1>

<table>
  <tr>
    <th>Name</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>

<% @authors.each do |author| %>
  <tr>
    <td><%= author.name %></td>
    <td><%= link_to 'Show', author %></td>
    <td><%= link_to 'Edit', edit_author_path(author) %></td>
    <td><%= link_to 'Destroy', author, method: :delete, data: { confirm: 'Are you sure?' } %></td>
  </tr>
<% end %>
</table>

<%= link_to 'New Author', new_author_path %>

And for each author, you click show, to bring up their own page.

<p>
  <b>Name:</b>
  <%= @author.name %>
</p>

<%= link_to 'Edit', edit_author_path(@author) %> |
<%= link_to 'Back', authors_path %>

Now I have the same set up for books, where the user can enter new books, show and edit books in the database.

I then set up a model called authorbooks that holds a relation ship between authors and books using has_many, and belongs_to in the models for author.rb, book.rb and authorbook.rb.

I am wanting the show page of the author to display every book that they are related to.

How would I go about this? I am new to rails and still learning so please remember when answering. Thanks in advance.

EDIT model code for each model:

author.rb

class Author < ActiveRecord::Base
  attr_accessible :name

  validates :name, :presence => true

  has_many :authorbooks
  has_many :books, :through => :authorbooks
end

book.rb

class Book < ActiveRecord::Base
  attr_accessible :name

  validates :name, :presence => true

  has_many :authorbooks
  has_many :authors, :through => :authorbooks
end

authorbook.rb

class Authorbook < ActiveRecord::Base
  attr_accessible :author_id, :book_id

  belongs_to :book
  belongs_to :author
end

Solution

  • It would have been interesting to see the model code as well. I assume you have something like:

    class Author
      has_many :author_books
      has_many :books, :through => :author_books # this line might be missing,
                                                 # read in the api documentation about it.
    
    class AuthorBooks
      belongs_to :author
      belongs_to :book
    

    Now you can do something like:

    <h3>Related books</h3>
    
    <ul>
      <% @author.books.each do |book| %>
        <li><%= book.name %> <%= link_to "Details", book_path(book) %></li>
      <% end %>
    </ul>
    

    Without the :through line you could have done something like:

    @author.author_books.each do |ab|
      ... ab.book.name ...
    

    Note 1: you get N+1 load problems with the second example. See the eager loading chapter in A::R guide for more information about that.

    Note 2: Checkout HAML; much nicer than ERB