Rails Live Coding

jordantaylorj

JordanTaylorJ

Posted on January 16, 2023

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!

💖 💪 🙅 🚩
jordantaylorj
JordanTaylorJ

Posted on January 16, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Rails Live Coding
ruby Rails Live Coding

January 16, 2023