Ruby on Rails - Tips and Tricks

Episode #118 by Teacher's Avatar David Kimura

Summary

In this episode, we will go through some of the tips and tricks that we often take for granted. We will be looking at nested routes, scopes, migrations and more.
rails tips tricks 14:53

Resources

Download Source Code

Summary

# Terminal
rails g scaffold brand name
rails g scaffold product brand:references name 'price:decimal{5,2}'
rails db:migrate
rails db:seed
rails routes

# Gemfile
gem 'faker'

# db/seeds.rb
10.times do
  Brand.create do |brand|
    brand.name = Faker::Company.name
    100.times do
      brand.products.new do |product|
        product.name = Faker::Commerce.product_name
        product.price = Faker::Commerce.price
      end
    end
  end
end

# models/brand.rb
class Brand < ApplicationRecord
  has_many :products, dependent: :destroy
end

# models/product.rb
class Product < ApplicationRecord
  belongs_to :brand #, optional: true

  scope :cheap_products, -> { where(price: 0..50.00).order(price: :asc) }
  # scope :expensive_products, -> { where(price: 50.01..Float::INFINITY).order(price: :asc) }
  scope :expensive_products, -> { where(price: 50.01..1.0/0.0).order(price: :asc) }
  
  # def self.cheap_products
  #   where(price: 0..50.00).order(price: :asc)
  # end
end

# config/routes.rb
Rails.application.routes.draw do
  resources :brands do
    resources :products
  end
end

# products_controller.rb
class ProductsController < ApplicationController
  before_action :set_brand, except: [:index]
  before_action :set_product, only: [:show, :edit, :update, :destroy]

  def index
    @brand = Brand.includes(:products).find(params[:brand_id])
    @products = @brand.products
  end

  def show
  end

  def new
    @product = @brand.products.new
  end

  def edit
  end

  def create
    @product = @brand.products.new(product_params)

    if @product.save
      # redirect_to brand_product_path(@brand, @product), notice: 'Product was successfully created.'
      redirect_to [@brand, @product], notice: 'Product was successfully created.'
    else
      render :new
    end
  end

  def update
    if @product.update(product_params)
      redirect_to [@brand, @product], notice: 'Product was successfully updated.'
    else
      render :edit
    end
  end

  def destroy
    @product.destroy
    # redirect_to brand_products_path(@brand), notice: 'Product was successfully destroyed.'
    redirect_to [@brand, :products], notice: 'Product was successfully destroyed.'
  end

  private
    def set_brand
      @brand = Brand.find(params[:brand_id])
    end
    
    def set_product
      @product = @brand.products.find(params[:id])
    end

    def product_params
      params.require(:product).permit(:brand_id, :name, :price)
    end
end

# products/_form.html.erb
<%= form_with(model: [@brand, product], local: true) do |form| %>

# products/_product.html.erb
<tr>
  <td><%= product.name %></td>
  <td><%= product.price %></td>
  <td><%= link_to 'Show', [@brand, product] %></td>
  <td>
    <%# link_to 'Edit', edit_brand_product_path(@brand, product) %>
    <%= link_to 'Edit', [:edit, @brand, product] %>
  </td>
  <td><%= link_to 'Destroy', [@brand, product], method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>