Search code examples
ruby-on-railsrubyactiverecordmodelcontroller

Book.all action displaying empty results


I'm new to Ruby On Rails development, I'm building an API containing the class user, book, author, and shelf. When I call Book.all to retrieve all the books in the Database, I get [] in return and don't know what could be the problem. Here are the book migration, book model, and book controller files:

class CreateBooks < ActiveRecord::Migration[7.0]
  def change
    create_table :books do |t|
      t.string :title
      t.references :user, null: false, foreign_key: true

      t.timestamps
    end
  end
end
class Book < ApplicationRecord
  belongs_to :user
  belongs_to :author
  belongs_to :shelf
end
class Api::BooksController < ApplicationController
  def index
    books = Book.all
    render json: book
  end
  
  def show
    book = Book.find(params[:id])
    render json: book
  end
  
  def create
    book = Book.new(book_params)
  
    if book.save
      render json: book, status: :created
    else
      render json: { errors: book.errors.full_messages }, status: :unprocessable_entity
    end
  end
  
  def destroy
    book = Book.find(params[:id])
    if book.destroy
      render json: { message: 'Book was deleted successfully' }
    else
      render json: { error: 'Failed to delete the Book' }, status: :unprocessable_entity
    end
  end
  
  private
  
  def book_params
    params.require(:book).permit(:title)
  end
end

I was expecting to see the names of the books I've created in the database. Here is how I've done it in Rails console:

book = Book.new(title: "Pearl of Great Price")  

Solution

  • There are a couple of errors you should address:

    1. Here, in the controller action, you should use the books local variable, which seems to be a typo (books vs book):
    def index
      books = Book.all
      render json: books
    end
    
    1. In the Rails console, you should "save" the record to the database (the new method only initializes the record in memory, see the docs):
    Book.create(title: "Pearl of Great Price")  
    
    # You can also do: new + save
    book = Book.new(...)
    book.save
    

    You'll probably need to pass a user too, since you have a belongs_to :user and a DB constraint, so it needs to be something like:

    Book.create(title: "...", user: User.last)  
    

    And finally, as you defined more relations in your model, you'll need to send them in order to create "valid" books:

    Book.create(title: "...", user: User.last, author: Author.last, shelf: Shelf.last)
    

    Of course, you'll need to create those records first. If you don't want all those relations to be mandatory, you can also add the optional: true setting in your belongs_to associations. More info: https://guides.rubyonrails.org/association_basics.html.