Reflections — My first Rails Application
By: Milan Parmar
Tags: Books, Flatiron School, Web Development, Software Engineering, Ruby on Rails

Reflections Login Page utilising Facebook OmniAuth

What a journey! Rails has been quite the framework that has put me on some challenging roads however I am grateful for all that I have learnt and applied.

As with every project/app, I begin with what purposeful application I would like to build. I wanted to create an application that allows users to sign up, add their inspirational/spiritual books to their profile and finally add their reflective thoughts on these books.

Which models and attributes do I need then? Simple: User, Books & Reflections.

A user would have many books, many reflections and many “reflected” books through reflections.

has_many :owned_books, foreign_key: :owner_user_id, class_name: "Book"

has_many :reflections, foreign_key: :reflection_user_id

has_many :reflection_books, through: :reflections

A books would belong to a user, have many reflections and many “reflection” users through reflections. I also included a has_one_attached :image in order to upload a book cover image for each book.

has_one_attached :image

has_many :reflections, foreign_key: :reflection_book_id

has_many :reflection_users, through: :reflections

belongs_to :owner_user, class_name: "User", optional: true

A reflection would belong to both a user and a book.

belongs_to :reflection_user, class_name: "User"

belongs_to :reflection_book, class_name: "Book"

After creating the database and association models, I moved onto the routes that are required and then I worked on my controllers. Working on the controller methods, I saw a lot of repetition and we all know the drill…DRY! So, I either created before action methods under private and helper methods in my application_controller.rb file.

For example, in my User controller:

class UsersController < ApplicationController

...

before_action :set_user, only: [:show, :edit, :settings, :destroy] ...



private def set_user

@user = User.find(params[:id])

end def access_self

if @user = current_user

@user

end

end def user_params

params.require(:user).permit(:username, :password, :email)

end end

I had to deal a lot with form_for which is a brillant helper to create forms requiring models. Form_for is pretty neat when dealing with validation errors as you can simply call the instance variable with .errors to get standard error messages. Apart from form_for , I also saw many button_to helpers across my application. DRY, DRY, you guessed it…DRY!

I had to find a way to clean up my app and so used partials to help me access embedded ruby code across my erb files and create helper methods, where necessary.

I must admit, that the scope method took a lot of thinking power as I seemed to over complicate what I was trying to achieve. My aim was to join the reflections table with my users > access every user that has at least one reflection > show the user ’s in descending order from the time they were created > show the particular user with the book that they just reflected on. Well…yeah 🙃 So instead I did:

scope :with_reflections, ->{ joins(:reflections).order(created_at: :DESC) }

Which does everything I wanted except for showing the particular user with the book that they just reflected on. I can live with that, not too bad. 😁

I love the idea of nested routes and objects. What a brilliant way of associating objects smoothly. First step: create the nested routes:

(In my case)

resources :books do

resources :reflections, only: [:new, :edit, :show]

end

Next, using build within my controller to associate the reflection with the book :

@reflection = @book.reflections.build

Then, seeing the lovely URL e.g.,

I saw many similarities with Sinatra and at times, I was extremely lost when hands on with the project but what a great way to learn hey — being stuck and tackling through it! I’m looking forward to the next project and creating other rail web applications! 💻