Problem z "includes"

Mam dwa modele:

class Booking < ActiveRecord::Base
belongs_to :guest
end

class Guest < ActiveRecord::Base
has_many :bookings
end

Kontroler do booking wygląda tak:

class BookingsController < ApplicationController
def index
@bookings = Booking.includes(:guest).all
end
end

Zawartość dwóch tabeli tj. bookings i guests chcę wyświetlić w jednym widokiem:

/index.html.erb

lista

<% @bookings.each do |booking| %>

<%= booking.id %>

<%= booking.date_in %>

<%= booking.date_out %>

<%= booking.guest.email %>

<%= booking.guest.name %>

<% end %>

jednak cały czas dostaję informację o błędzie:

undefined method `email’ for nil:NilClass

Jak widzisz booking jest nilem, masz jakieś dane zseedowane do bazy? Wrzuć binding.pry do controllera, zobacz do czego masz dostęp, sprawdź asociację w terminalu (np. User.last.guest.email)

W obydwóch tablicach znajdują się dane. Błąd undefined method `email’ for nil:NilClass pojawia się tylko dla:
<%= booking.guest.email %>
<%= booking.guest.name %>

booking.guest jest nil-em

Pokaż migracje i seeds.rb bo nil jednak występuje w booking.guest_id :confused:

Użyj <%= booking.guest.try(:email) %>
Jeżeli quest będzie nil’em , to funkcja try() zwróci pusty ciąg zamiast błędu w przypadku konstrukcji:
booking.guest.email

<%= booking.guest.try(:email) %> nie zwraca danych z tablicy guests (tablica zawiera wpisane dane), zwraca jedynie jeden rekord z tablicy bookings:

lista
1
10-10-2017
12-10-2017

moje migracje:

class CreateGuests < ActiveRecord::Migration
def change
create_table :guests do |t|
t.string :name
t.string :email
t.timestamps null: false
end
end
end

class CreateBookings < ActiveRecord::Migration
def change
create_table :bookings do |t|
t.string :date_in
t.string :date_out
t.belongs_to :guest, index: true, foreign_key: true

  t.timestamps null: false
end

end
end

Istnieją odwołania w tabeli bookings do usuniętych wpisów tabeli guests … brak obsługi dependent: … w Guest AR

chociaż nie wiem czy są możliwe takie odwołania :blush: patrząc na:

jest możliwe FK sprawdzany tylko przy create/update w bookings :sunny:

Musisz w końcu zdać sobie sprawę, że “includes” nie tworzy połączenia inner join między tabelami, a jedynie outer join. Poszukaj na czym polega różnica, a zrozumiesz, dlaczego masz nil po jednej ze stron złączenia.

Czyli idąc w ślad za dokumentacją[1] zamiast konstrukcji:

@bookings = Booking.includes(:guest).all

powinno być:

@bookings = Booking.joins(:guest)

Zgadza się?

[1] http://guides.rubyonrails.org/active_record_querying.html

Działą z następującym zapisem:
@bookings = Booking.joins(:guest)

ale dodatkowo okazało się że w tabeli Bookings kolumna guest_id była nil’em . Czyli brakowało “połączenia” pomiędzy tabelami Bookings-Guests.

Bardzo wszystkim dziękuję za poświęcony czas i podpowiedzi.