Rails Live Coding
Tags: ruby, rails, livecoding, database
Published: 2023-01-16 21:55:59

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/07gbw97ss0urw7jh18ur.png)
Check out my [repo](https://github.com/JordanTaylorJ/book_club) 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))
  }
```

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 
```
`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 
```

# 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'

```

## 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 
```

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 
```

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 
```

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!