DEV Community

JordanTaylorJ
JordanTaylorJ

Posted on • Updated on

Rails Live Coding

My project is a website for a book club that allows users to share books and discuss them. Each review/comment has an option to add a heart or a favorite.

The objective was to add a button to my book display page that displays the book with the highest favorite count.

My schema looks like this:
Application Schema
Check out my repo for more context.

Solution

In the front I added a variable favoriteBook to state, a JSX button, and the onClick with the following fetch request:

const handleFavoriteClick = () => {
    fetch('/books/favorite')
    .then(res => res.json())
    .then(res => setFavoriteBook(res))
  }
Enter fullscreen mode Exit fullscreen mode

From there, I added a custom route in routes.rb.
get '/books/favorite', to: 'books#favorite'

Next, in my Book model I added a method to determine the number of favorited reviews on a book instance.

    def favorite_count
        count = 0
        self.reviews.each do |review| 
            if review.favorite == true
                count += 1
            end
        end 
        count
    end 
Enter fullscreen mode Exit fullscreen mode

self above refers to an instance of Book in the class Book. I started the count variable at zero, then iterated through each review to see if the favorite boolean was true. If it was, I added one to the count.

In book_serializer.rb I added :favorite_count to my attributes in order for it to be available to the frontend.

Finally, in books_controller.rb I was able to utilize the favorite_count method. I set the highest_count variable to zero and a case 'No books have been favorited' incase of a scenario where there are no favorites. I iterated through each book and determined the book with highest number of favorited reviews.

    def favorite
        highest_count = 0
        favorite_book = 'No books have been favorited.'
        Book.all.each do |book|
            if book.favorite_count > highest_count 
                highest_count = book.favorite_count
                favorite_book = book
            end
        end
        render json: favorite_book, status: :ok 
    end 
Enter fullscreen mode Exit fullscreen mode

Other Considerations

Routing

When I was initially fetching to the custom route I kept getting back content for books#index. I later determined that in order for my custom route to work on books_controller.rb, I needed to remove resources :books, only: [:show, :create] This only: was blocking the custom route. I ended up listing out the :show and :create routes along with :favorite.

  get '/books/show', to: 'books#show'
  post '/books', to: 'books#create'
  get '/books/favorite', to: 'books#favorite'

Enter fullscreen mode Exit fullscreen mode

Controller Clean-Up

The #favorite action in books_controller.rb was originally made with only a highest_count variable, and I was trying to save the book there.

    def favorite
        highest_count = ""
        Book.all.each do |book|
            if book.favorite_count > highest_count 
                highest_count = book
            end
        end
        render json: favorite_book, status: :ok 
    end 
Enter fullscreen mode Exit fullscreen mode

This failed by the second iteration because I was comparing an integer to an instance of book.

The solution I made was to create two variables, one for the count and another for the book itself:

    def favorite
        highest_count = 0
        favorite_book = 'No books have been favorited.'
        Book.all.each do |book|
            if book.favorite_count > highest_count 
                highest_count = book.favorite_count
                favorite_book = book
            end
        end
        render json: favorite_book, status: :ok 
    end 
Enter fullscreen mode Exit fullscreen mode

This was a success, but I thought could be cleaner.
Another solution would be as follows:

    def favorite
        favorite_book = Book.new(title: 'No books have been favorited.')
        Book.all.each do |book|
            if book.favorite_count > favorite_book.favorite_count 
                favorite_book = book
            end
        end
        render json: favorite_book, status: :ok 
    end 
Enter fullscreen mode Exit fullscreen mode

Here, I'm comparing the favorite_count of the current highest book to the favorite_count of the book in the current iteration. I created an unsaved instance of Book with no reviews (and therefore no favorites) in order to make the first comparison.

Tips for Rails Live Coding

  • Determine where in the schema the information you're looking for is. In my scenario, my favorite attribute was on every individual review nested under books. I needed to calculate a count for each instance of Book before I could compare to find the highest favorite_count.

  • Follow the call stack. First I needed a button to press, then the routing, then an empty controller action. From there I had to determine the connection between all my ruby files (controllers, serializers, and models) to ensure I was utilizing them properly. Remember the models represent an instance of a table item. Serializers are for data display to frontend. Controller is sending out the response.

  • Read error messages carefully. They're helpful if you take the time to understand the feedback. Pop in a debugger or binding.pry to take a closer look at whats happening.

Happy coding!

Top comments (0)