Skip to content

Instantly share code, notes, and snippets.

@nantrinh
Last active October 24, 2019 08:19
Show Gist options
  • Save nantrinh/ab85fe1e4cca09d33a75989a4a230d47 to your computer and use it in GitHub Desktop.
Save nantrinh/ab85fe1e4cca09d33a75989a4a230d47 to your computer and use it in GitHub Desktop.
rails_lesson_1

Introduction

This article summarizes what I learned in Lesson 1 of the Launch School 5301 Rails Course. I used Rails 6 and Ruby 2.5.3.

Instructions

Create an app called PostIt based on the entity relationship diagram. ERD

Create routes for posts and categories. Prevent the delete route from being accessed.

Create controllers and views to view:

  • all posts
  • a specific post and its associated categories
  • all categories
  • a specific category and its associated posts

Change the association name between posts and user to posts and creator, so we have a better idea of the relationship of the association.

Create new application

  • rails new postit
  • Run cd postit
  • Run rails server
  • Navigate to http://localhost:3000 in browser and verify that a welcome page is shown.

Create tables

After creating each migration file and modifying its contents:

  1. Run rails db:migrate.
  2. Run cat db/schema.rb to inspect the schema. We want to check if the migration had the intended effects.

Users

rails g migration CreateUsers

def change
  create_table :users do |t|
    t.string :username

    t.timestamps
  end

Posts

rails g migration CreatePosts

def change
  create_table :posts do |t|
    t.string :title
    t.string :url
    t.text :description
    t.belongs_to :user

    t.timestamps
  end

Comments

rails g migration CreateComments

def change
  create_table :comments do |t|
    t.text :body
    t.belongs_to :user
    t.belongs_to :post

    t.timestamps
  end

Categories

rails generate migration CreateCategories

def change
  create_table :categories do |t|
    t.string :name

    t.timestamps
  end

PostCategories

rails generate migration CreatePostCategories

def change
  create_table :post_categories do |t|
    t.belongs_to :post
    t.belongs_to :category

    t.timestamps
  end
end

Create models

  • Run rails console to open up the rails console.
  • After creating each model file, run reload! to reload the console.
  • Run [ModelName].all to verify that a SQL query is executed to select all rows from the appropriate table. We want to check that each model is hooked up with the appropriate table.

User

app/models/user.rb

class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  has_many :comments, dependent: :destroy
end

Post

app/models/post.rb

class Post < ApplicationRecord
  belongs_to :user
  has_many :comments, dependent: :destroy
  has_many :categories, through: :post_categories, dependent: :destroy
end

Comment

app/models/comment.rb

class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

Category

app/models/category.rb

class Category < ApplicationRecord
  has_many :posts , through: :post_categories, dependent: :destroy
end

PostCategory

app/models/post_category.rb

class PostCategory < ApplicationRecord
  belongs_to :post
  belongs_to :category
end

Check Associations

Run the following commands in the rails console and check that the output is as expected. If you encounter errors, try restarting the rails console (not just running reload!). It is assumed that the commands are run sequentially from one section to the next (e.g., commands in "1:M association between User and Post" are run before "1:M association between User and Comment".

1:M association between User and Post

nancy = User.create(username: "Nancy")
victor = User.create(username: "Victor")
chili = Post.create(title: "How to make chili oil", url: "woksoflife.com", description: "great recipe on how to make chili oil", user: nancy)
compost = Post.create(title: "How to make compost", url: "urbangardening.com", description: "compost recipe using coffee grounds", user: nancy)
bok_choy = Post.create(title: "Why bok choy is great for cats", url: "loveyourcats.com", description: "argument for more greens in your cat's diet", user: victor)

chili.user.username # "Nancy"
bok_choy.find(3).user.username # "Victor"
nancy.posts.map {|x| x.title} # ["How to make chili oil", "How to make compost"]
victor.posts.map {|x| x.title} # ["Why bok choy is great for cats"]

1:M association between User and Comment

Comment.create(body: "I agree!", user: nancy, post: bok_choy)
Comment.create(body: "This looks delicious!", user: victor, post: chili)
Comment.create(body: "I'm commenting on my own post.", user: nancy, post: chili)

nancy.comments.map {|x| x.body} # ["I agree!", "I'm commenting on my own post."]
victor.comments.map {|x| x.body} # ["This looks delicious!"]

1:M association between Post and Comment

chili.comments.map {|x| x.body} # ["This looks delicious!", "I'm commenting on my own post."]

M:M association between Post and Categories

recipes = Category.create(name: "recipes")
food = Category.create(name: "food")
cat = Category.create(name: "cat")

PostCategory.create(post: chili, category: recipes)
PostCategory.create(post: chili, category: food)
PostCategory.create(post: bok_choy, category: food)
PostCategory.create(post: bok_choy, category: cat)

recipes.posts.map {|x| x.title} # ["How to make chili oil"]
food.posts.map {|x| x.title} # ["How to make chili oil", "Why bok choy is great for cats"]
cat.posts.map {|x| x.title} # ["Why bok choy is great for cats"]

chili.categories.map {|x| x.name} # ["recipes", "food"]
bok_choy.categories.map {|x| x.name} # ["food", "cat"]

Create routes.

Create routes for posts and categories. Prevent the delete route (destroy action) from being accessed. config/routes.db

Rails.application.routes.draw do
  resources :posts, :categories, except: :destroy
end

Check that the output for rails routes -g posts and rails routes -g categories do not contain a route for the DELETE method.

Create controllers and views.

Create controllers and views to view:

  • all posts
  • a specific post and its associated categories
  • all categories
  • a specific category and its associated posts

Create controllers.

app/controllers/posts.rb

class PostsController < ApplicationController
  def index
    @posts = Post.all
  end

  def show
    @post = Post.find(params[:id])
  end
end

app/controllers/categories.rb

class CategoriesController < ApplicationController
  def index
    @categories = Category.all
  end

  def show
    @category = Category.find(params[:id])
  end
end

Create views.

After each view is created, navigate to the appropriate URL in the browser to verify that the response is as expected. Make sure your server is running before checking the URLs (run rails server).

posts#index

app/views/posts/index.html.erb localhost:3000/posts

<h1>Posts</h1>
 
<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>URL</th>
      <th>Description</th>
    </tr>
  </thead>
 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.title %></td>
        <td><%= post.url %></td>
        <td><%= post.description %></td>
        <td><%= link_to "Show", post %></td>
      </tr>
    <% end %>
  </tbody>
</table>

posts#show

app/views/posts/show.html.erb localhost:3000/posts/:id

<h1><%= @post.title %></h1>

<p> Tags: 
<% @post.categories.each do |category| %>
  <%= link_to category.name, category_path %>
<% end %>
</p>

<p>URL: <%= @post.url %></p>
<p>Description: <%= @post.description %></p>
<%= link_to "All Posts", posts_path %>

categories#index

app/views/categories/index.html.erb localhost:3000/categories

<h1>Categories</h1>

<ul>
<% @categories.each do |category| %>
  <li><%= link_to category.name.capitalize, category %></li>
<% end %>
</ul>

categories#show

app/views/categories/show.html.erb localhost:3000/categories/:id

<h1>Posts Tagged "<%= @category.name.capitalize %>"</h1>

<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>URL</th>
      <th>Description</th>
    </tr>
  </thead>
 
  <tbody>
    <% @category.posts.each do |post| %>
      <tr>
        <td><%= post.title %></td>
        <td><%= post.url %></td>
        <td><%= post.description %></td>
        <td><%= link_to "Show", post %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<%= link_to "All Categories", categories_path %>

Change the association name.

  • In app/models/post.rb, change the line belongs_to :user to belongs_to :creator, class_name: "User", foreign_key: "user_id".
  • Open rails console and check that Post.first.creator returns the first user object, and Post.first.user now throws a NoMethodError.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment