Ruby on Rails
01 / 04

Rails MVC & Routing

Rails MVC & Routing

Rails implements a strict MVC pattern. The router maps URLs to controller actions. Controllers coordinate between models and views. Mastering routes.rb and controller conventions covers the vast majority of web request handling in Rails.

routes.rb

# config/routes.rb

Rails.application.routes.draw do
  # resources generates 7 RESTful routes (index/show/new/create/edit/update/destroy)
  resources :articles

  # Nested resources
  resources :posts do
    resources :comments, only: [:index, :create, :destroy]
  end

  # Singular resource (no :id in URL — e.g. user profile)
  resource :profile, only: [:show, :edit, :update]

  # Namespace — groups routes and controllers under a prefix
  namespace :admin do
    resources :users
    resources :analytics, only: [:index]
  end
  # => /admin/users, controllers in app/controllers/admin/users_controller.rb

  # Scope — URL prefix without affecting controller namespace
  scope :api do
    resources :products
  end
  # => /api/products, controllers still in app/controllers/products_controller.rb

  # API versioning with module and scope
  scope :api do
    namespace :v1 do
      resources :users
    end
  end
  # => /api/v1/users, controller: Api::V1::UsersController

  # Member routes (operate on a specific resource)
  resources :articles do
    member do
      post :publish
      delete :archive
    end
    collection do
      get :featured     # /articles/featured
    end
  end

  # Concerns — shared route fragments
  concern :commentable do
    resources :comments
  end
  resources :posts, concerns: :commentable
  resources :photos, concerns: :commentable

  # Named routes
  get "/about", to: "pages#about", as: :about
  # => about_path, about_url helpers generated

  root "dashboard#index"
end
# Inspect routes
rails routes                           # All routes
rails routes -g article                # Filter by pattern
rails routes --expanded                # Show full details

# Route helpers generated by resources :articles:
# articles_path          → /articles         (index, create)
# new_article_path       → /articles/new     (new)
# article_path(article)  → /articles/:id     (show, update, destroy)
# edit_article_path(art) → /articles/:id/edit (edit)

Controllers

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  before_action :authenticate_user!              # Runs before every action
  before_action :set_article, only: [:show, :edit, :update, :destroy]
  before_action :authorize_author!, only: [:edit, :update, :destroy]

  def index
    @articles = Article.published.order(created_at: :desc).page(params[:page])
    # render :index is implicit — renders app/views/articles/index.html.erb
  end

  def show
    # @article already set by before_action
    respond_to do |format|
      format.html                          # renders show.html.erb
      format.json { render json: @article }
    end
  end

  def new
    @article = Article.new
  end

  def create
    @article = current_user.articles.build(article_params)
    if @article.save
      redirect_to @article, notice: "Article created successfully."
    else
      render :new, status: :unprocessable_entity
    end
  end

  def update
    if @article.update(article_params)
      redirect_to @article, notice: "Article updated."
    else
      render :edit, status: :unprocessable_entity
    end
  end

  def destroy
    @article.destroy!
    redirect_to articles_path, status: :see_other, notice: "Article deleted."
  end

  private

  def set_article
    @article = Article.find(params[:id])
  end

  # Strong parameters — whitelist what can be mass assigned
  def article_params
    params.require(:article).permit(:title, :body, :published, tag_ids: [])
  end

  def authorize_author!
    redirect_to root_path, alert: "Not authorized." unless @article.author == current_user
  end
end

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free