Ruby on Rails Framework

Introduction to Rails

Ruby on Rails is a web application framework written in Ruby that follows the Model-View-Controller (MVC) pattern and emphasizes convention over configuration.

Core Principles:

  • Don't Repeat Yourself (DRY)
  • Convention over Configuration
  • REST architectural style
  • Rapid development
  • Testing is built-in

Key Features:

  • Active Record ORM
  • Action Pack for handling requests
  • Action Mailer for emails
  • Active Storage for file uploads
  • Action Cable for WebSockets

MVC Architecture

Model

# app/models/user.rb
class User < ApplicationRecord
  has_many :posts
  has_many :comments
  
  validates :email, presence: true, uniqueness: true
  validates :username, presence: true, length: { minimum: 3 }
  
  before_save :normalize_email
  
  private
  
  def normalize_email
    self.email = email.downcase
  end
end

Controller

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :set_user, only: [:show, :edit, :update, :destroy]
  
  def index
    @users = User.all
  end
  
  def show
  end
  
  def create
    @user = User.new(user_params)
    
    if @user.save
      redirect_to @user, notice: 'User created successfully'
    else
      render :new
    end
  end
  
  private
  
  def user_params
    params.require(:user).permit(:email, :username, :password)
  end
end

Active Record

Associations

class User < ApplicationRecord
  has_many :posts
  has_many :comments
  has_one :profile
  has_and_belongs_to_many :roles
end

class Post < ApplicationRecord
  belongs_to :user
  has_many :comments
  has_many :tags, through: :post_tags
end

Querying

# Find records
User.find(1)
User.find_by(email: 'user@example.com')
User.where(active: true)

# Complex queries
User.joins(:posts)
    .where(posts: { published: true })
    .group('users.id')
    .having('count(posts.id) > ?', 5)

# Scopes
class Post < ApplicationRecord
  scope :published, -> { where(published: true) }
  scope :recent, -> { order(created_at: :desc).limit(5) }
end

Routing

RESTful Routes

# config/routes.rb
Rails.application.routes.draw do
  root 'home#index'
  
  resources :users do
    resources :posts
    member do
      get 'profile'
    end
    collection do
      get 'search'
    end
  end
  
  namespace :api do
    namespace :v1 do
      resources :users, only: [:index, :show]
    end
  end
end

Custom Routes

# Custom routes with constraints
get 'posts/:year/:month/:day' => 'posts#show',
    constraints: {
      year: /\d{4}/,
      month: /\d{1,2}/,
      day: /\d{1,2}/
    }

# Route concerns
concern :commentable do
  resources :comments
end

resources :posts, concerns: :commentable
resources :photos, concerns: :commentable

Views and Templates

ERB Templates


Users

<% @users.each do |user| %> <% end %>
Username Email Actions
<%= user.username %> <%= user.email %> <%= link_to 'Show', user %> <%= link_to 'Edit', edit_user_path(user) %>

Layouts and Partials




  
    
    
    

    <%= content_for?(:title) ? yield(:title) : "Default" %>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag 'application' %>
  


  
    <%= render 'shared/header' %>
    <%= yield %>
    <%= render 'shared/footer' %>
  



<%= form_with(model: @user, local: true) do |f| %>
  
<%= f.label :username %> <%= f.text_field :username %>
<%= f.submit %> <% end %>

Testing

Model Tests

# test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  test "should not save user without email" do
    user = User.new
    assert_not user.save, "Saved user without email"
  end
  
  test "should validate email format" do
    user = users(:valid)
    user.email = "invalid_email"
    assert_not user.valid?
  end
end

Controller Tests

# test/controllers/users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest
  test "should get index" do
    get users_url
    assert_response :success
  end
  
  test "should create user" do
    assert_difference('User.count') do
      post users_url, params: { 
        user: { email: 'test@example.com', username: 'test' } 
      }
    end
    assert_redirected_to user_url(User.last)
  end
end

Security

Authentication

# Using Devise
# Gemfile
gem 'devise'

# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :confirmable, :lockable

  def active_for_authentication?
    super && active?
  end
end

Authorization

# Using Pundit
class PostPolicy < ApplicationPolicy
  def update?
    user.admin? || record.author == user
  end
  
  class Scope < Scope
    def resolve
      if user.admin?
        scope.all
      else
        scope.where(author: user)
      end
    end
  end
end

Deployment

Deployment Checklist:

  • Configure production environment
  • Set up database
  • Configure web server (Nginx/Apache)
  • Set up SSL certificates
  • Configure background jobs

Production Configuration

# config/environments/production.rb
Rails.application.configure do
  config.cache_classes = true
  config.eager_load = true
  config.consider_all_requests_local = false
  config.action_controller.perform_caching = true
  config.public_file_server.enabled = true
  config.assets.compile = false
  config.active_storage.service = :amazon
  config.log_level = :info
  config.force_ssl = true
end