Tri5tal
Tri5tal

Reputation: 3

Rails - Returning list of incorrect ids

I have an app including Dog, Events and Booking models. Each event has many bookings, each dog has many bookings but each booking belong to an event and has one dog.

On the view for Events it should list all bookings with that id and the details of the linked dog.

I was having a lot of trouble with "Rails Error: undefined method ` ' for nil:NilClass" but then realised the problem was that it is retrieving a list of dogs based on the booking id and not the dog_id field.

In the console I can see that this is the SQL query being generated and what I think is the source of the error but I can't figure out why:

SELECT "dogs".* FROM "dogs" INNER JOIN "bookings" ON "dogs"."id" = "bookings"."id" WHERE "bookings"."event_id" = ?  [["event_id", 1]]

I've spent days combing Stack Overflow and Google to figure out where I've gone wrong but am a bit lost. Here are the models:

class Event < ActiveRecord::Base
has_many :bookings
has_many :dogs, :through => :bookings, :foreign_key => "dog_id"
end

class Dog < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 255 }
validates :breed, presence: true, length: { maximum: 255 }
belongs_to :owner
validates :owner_id, presence: true
has_many :bookings
has_many :events, through: :bookings, :foreign_key => "event_id"
end

class Booking < ActiveRecord::Base
belongs_to :event
has_one :dog, :foreign_key => "id"
validates :event_id, presence: true
validates :dog_id, presence: true
end

The controllers

class EventsController < ApplicationController
  before_action :logged_in_user

  def index
    @events = Event.paginate(page: params[:page])
  end


  def show
    @event = Event.find(params[:id])
    @bookings = @event.bookings.paginate(page: params[:page])

...

class DogsController < ApplicationController

  def show
    @dog = Dog.find(params[:id])
  end

  def new
    @dog = Dog.new
  end

...

class BookingsController < ApplicationController
end

And finally the show view for Events and the _booking partial it renders:

<% provide(:title, @event.name) %>
<div class="row">
  <aside class="col-md-4">      
    <section class="event_info">
      <h1><%= @event.name %></h1> - <%= @event.category %>
      <span><b><%= @event.date %></b> <%= @event.start %> - <%= @event.finish %>    </span>
      <span><b>Location:</b> <%= @event.location %></span>
      <%-# Calculated occupany figure goes in line below. -%>
      <span><b>Capacity: </b>X / <%[email protected] %></span>
    </section>
  </aside>
  <div class="col-md-8">
    <section class="event_notes_header">
      Description
    </section>
    <section class="event_notes_body">
      <%= @event.description %>
    </section>
    <section class="event_notes_header">
      Notes
    </section>
    <section class="event_notes_body">
      Event notes will be displayed here...
    </section>
  </div>
  <div class="col-md-8">
    <% if @event.bookings.any? %>
      <h3>Bookings (<%= @event.bookings.count %>)</h3>
      <ol class="bookings">
        <%= render @bookings %>
      </ol>
      <%= will_paginate @bookings %>
    <% end %>
  </div>
</div>   

_booking.html.erb

<li id="booking<%= booking.id %>">
  <span class="event"><%= link_to booking.event.name, booking.event %></span>
  <span class="dog"><%= link_to booking.dog.name, booking.dog %></span>
</li>

Apologies if I've missed anything or if the code has gotten a little convoluted - this is where I am after several days of plugging stuff in and out to try and fix this error.

Upvotes: 0

Views: 59

Answers (1)

Almaron
Almaron

Reputation: 4147

The first problem I see here is in your associations (and I believe it's the main reason this crap is happening). Your Booking model is a typical joining model for a has_many :through association. But the inner associations are not set properly. If you look at the association between Dog and Booking, you'll notice that there are two has_* paths and no belongs_to path (wich needs to be on the model, that has the dog_id in it, in this case the Booking model).

So your first step is to set the associations properly. You should change

has_one :dog, :foreign_key => "id"

to

belongs_to :dog

Second thing I recommend you do with those associations is getting rid of those foreign_key calls, that might just confuse you and are not needed as long as you're folowing conventions.

Upvotes: 1

Related Questions