Category: Ruby on Rails

  • JavaScript

    In this chapter, you will learn how to integrate JavaScript functionality into your Rails application, and how you can use external JavaScript packages. This chapter also introduces Turbo which is used for creating fast, modern web applications without having to reach for a client-side JavaScript framework.

    In modern web development, we often break our JavaScript into many smaller, manageable files (modules). We take these separate JavaScript files (along with assets like CSS and images) and bundle them into a smaller number of optimized files that the browser can then load more efficiently. This process is performed by JS bundlers.

    The Role of JS Bundlers

    A JS bundler typically does the following −

    • Module Resolution: Creates a dependency graph based on the relationships between your JavaScript files
    • Bundling: Take the dependent modules and combine them into one or more bundle files to reduce the number of HTTP requests by the browser. Bundlers also integrate with other tools to transform your code. For example, transpilation which means Converting newer JavaScript syntax (ES6+, JSX, TypeScript) into older, more widely supported JavaScript versions; minification (to reduce its file size) and apply various optimizations.
    • Asset Handling: Some bundlers can also handle other types of assets, like CSS, images, and fonts, often processing them through loaders and plugins.
    Role of JS Bundlers

    When you create a new Rails application, you can specify the JavaScript bundler webpack, esbuild, rollup, etc.

    Webpack JS Bundler

    Webpack is a static module bundler for modern JavaScript applications. It builds a dependency graph from one or more entry points and then combines every module your project needs into one or more bundles, as the static assets to serve your content from.

    Railsnew myapp --javascript=webpack 
    

    Esbuild JS Bundler

    esbuild is a very fast bundler, good for modern apps. It is a free and open-source module bundler and minifier for JavaScript and CSS written in Go. It supports TypeScript, JSX, tree-shaking and is extensible through plugins.

    Railsnew myapp --javascript=esbuild 
    

    Rollup JS Bundler

    Rollup is another JS module bundler which compiles small pieces of code into something larger libraries by using the new standardized format for code modules included in the ES6 revision of JavaScript.

    Railsnew myapp --javascript=rollup 
    

    To skip JavaScript support, you can create a Rails application with the following command line

    Railsnew myapp --skip-javascript 
    

    Since version 7, Rails uses ES modules with no build step. ImportMap is the default.

    Railsnew myapp --javascript=importmap 
    

    Installing a JavaScript Runtime

    If you are using esbuild, Rollup.js, or Webpack to bundle your JavaScript in your Rails application, Node.js and Yarn must be installed.

    Install Node.js

    For Windows, download the installer (https://nodejs.org/dist/v22.15.0/node-v22.15.0-x64.msi) from the official website and run the wizard. For other OS platforms, obtain the download files from https://nodejs.org/en/download.

    Install Yarn

    It is recommended to install Yarn through the npm package manager, which comes bundled with Node.js when you install it on your system.

    Once you have npm installed, you can run the following both to install and upgrade Yarn −

    npm install --global yarn
    

    Turbo

    Rails also installs Turbo to speed up your application. It reduces the amount of custom JavaScript that most web applications will need to write and fast, modern, progressively enhanced web applications.

    Turbo Drive, Turbo Frame and Turbo Streams are the components of Turbo.

    • Turbo Drive speeds up the page load process.
    • Turbo Frame allows predefined parts of a page to be updated on request.
    • Turbo Streams allow you to broadcast changes made by other users over WebSockets and update pieces of a page after a Form submission without requiring a full page load.

    Turbo lets you send HTML from the server which updates parts of the page dynamically, without any custom JavaScript.

  • Action Text

    In this chapter, you will learn how to handle rich text content in a Rails application with the help of Action Text component.

    We will cover the following topics in this chapter:

    • What Action Text is, and how to install and configure it.
    • How to create, render, style, and customize rich text content.

    What is Action Text?

    Installing Action Text enables you to display the rich text content – text that can including formatting features such as bold, italics, colors, fonts, etc. Action Text stores the rich text content in a table, then attach it to any of our models.

    Action Text component comes with a WYSIWYG editor called Trix. You can provide a user-friendly interface in your application (similar to what you see in the email composer in Gmail application).

    For this chapter, we start by creating a new Rails application:

    rails newBlogApp

    Then, inside the application, let’s generate a scaffolded Post resource and run migrations.

    rails generate scaffold Post title:string
    rails db:migrate

    Next, add a root route for our Post’s index view to the top of our routes.rb file.

    Rails.application.routes.draw do
      root to:"posts#index"
      resources :postsend

    Install Action Text

    To add the rich text support, install Action Text component, followed by running migrations again.

    rails action_text:install
    rails db:migrate

    This creates the files app/javascript/application.js and app/assets/stylesheets/actiontext.css. The second migration creates tables for Active Storage blobs and attachments (action_text_rich_textsactive_storage_blobsactive_storage_attachmentsactive_storage_variant_records)

    The application.js file shows that trix and actiontext support has been added.

    import "@hotwired/turbo-rails"
    import "controllers"
    
    import "trix"
    import "@rails/actiontext"

    You also need to import actiontext.css in the application’s main CSS file (application.css) −

    @import"./actiontext.css";

    The Action Text support hasn’t been activated yet. Start the Rails server and visit http://localhost:3000/posts/new page.

    Start the Rails server

    ActionText Setup

    We need to add a content field in the Post model.

    classPost<ApplicationRecord
      has_rich_text :contentend

    Presently, the new Post form only has the text input field for title. Let us add rich_text_area input type (provided by ActionText) in the app/views/posts/_form.html.erb template (shown in bold)

    <%= form_with(model: post) do |form| %>
      <% if post.errors.any? %>
    
    &lt;div style="color: red"&gt;&lt;h2&gt;&lt;%= pluralize(post.errors.count, "error") %&gt; prohibited this post from being saved:&lt;/h2&gt;
      &lt;ul&gt;
        &lt;% post.errors.each do |error| %&gt;
          &lt;li&gt;&lt;%= error.full_message %&gt;&lt;/li&gt;&lt;%end%&gt;
      &lt;/ul&gt;&lt;/div&gt;&lt;%end%&gt;
    <div><%= form.label :title, style: "display: block" %>
    &lt;%= form.text_field :title%&gt;
    </div><div class="field"><%= form.label :content %>
    &lt;%= form.rich_text_area :content%&gt;
    </div><div><%= form.submit %> </div><%end%>

    You also have to modify the show view app/views/posts/show.html.erb to be able to display the contents of new post.

    <p style="color: green"><%= notice %></p>
    <p>
      <strong>Title:</strong>
      <%[email protected] %>
    </p><p><strong>Content:</strong><%= @post.content.to_s.html_safe %>
    </p>
    
    <div>
      <%= link_to "Edit this post", edit_post_path(@post)%> |
      <%= link_to "Back to posts", posts_path %><%= button_to "Destroy this post",@post, method::delete%>
    </div>

    Make sure the PostsController has its post_params method allows title and content fields −

    defpost_params
       params.require(:post).permit(:title,:content)end

    That’s it. Save all the changes and run the server. The /posts/new route provides a trix editor for the content field.

    Save all the changes and run the server

    Click on the Create Post. The application displays the confirmation of the post creation with the help of show view.

    Save all the changes and run

    Adding Embedded Images

    In this chapter, you learned how to add rich text editor in your blogging app. You can add Embedded Images and Attachments support. For this, you will need to install the image_processing gem.

    Add the following in the application’s Gemfile −

    gem 'image_processing','~> 1.2'

    And then run the following command −

    bundle install
    

    The image_processing gem is used by Active Storage to things such as resize, crop, and optimize images, generate thumbnails for embedded images and convert images to different formats (JPEG, PNG, WebP, etc.).

  • Active Job

    The Active Job framework in Rails is extremely helpful for declaring background jobs and executing them asynchronously.

    Applications that involve background tasks such as sending emails, pushing notifications, background processing of CSV files and backing up the databases, integration with external apps through APIs, handling file uploads, etc., can be scheduled with Active Job framework.

    Emails with Active Job

    As explained in the previous chapter (Ruby on Rails – Sending Emails), there is a welcome_email() method in the UserMailer class.

    classUserMailer<ApplicationMailer
      default from:" GMAIL_USERNAME"defwelcome_email(user)@user= user
    
    mail(to:@user.email, subject:"Welcome to My Awesome Site!")endend</pre>

    Next, you need to create an Active Job with the following command:

    rails generate job send_emails
    

    This creates a custom job (SendEmailsJob) to handle the email-sending process asynchronously.

    Active Job provides a default perform() method which you need to override to call the welcome_email() method from the UserMailer class.

    classSendEmailsJob<ApplicationJob
      queue_as :defaultdefperform(user)UserMailer.welcome_email(user).deliver
      endend

    You now need to install a queuing service to handle the background jobs. We have a variety of background queuing libraries such as delayed jobssidekiqrescue, and so on.

    We will be using Sidekiq for the active job. For that, we must add a gem of sidekiq into Gemfile:

    gem 'sidekiq'
    bundle install
    

    However, you need to let Rails know that this gem is to be used for background processing. So, edit your application.rb to set the active_job.queue_adapter.

    moduleMyApplicationclassApplication<Rails::Application# make sure the adapter's gem has been included in your Gemfile.
    
    config.active_job.queue_adapter =:sidekiqendend</pre>

    Enqueuing the job

    After configuring queueing backend, you must add your job to the queue. Enqueue a job for execution when the queuing system is available. Along with it, the queue will change whenever the time changes. You may set times for when a task needs to be completed after a month or to be executed as soon as possible.

    Considering that SendEmailsJob is the name of our job, the multiple techniques listed below can be used to achieve enqueuing options.

    waitEnqueues the job with the specified delay
    wait_untilEnqueues the job at the time specified
    queueEnqueues the job on the specified queue
    priorityEnqueues the job with the specified priority

    For example,

    SendEmailsJob.set(wait:1.week).perform_later(user)

    This statement schedules sending the email 1 week from now. Or,

    SendEmailsJob.set(wait_until:Date.tomorrow.noon).perform_later(user)

    Will start the job tomorrow at noon.

    Recent versions of Ruby on Rails do not require you to generate a custom job when you're just using ActionMailer with deliver_later. To enable Active Job in your Rails application for sending emails asynchronously (such as when a User is created), you just need to queue the email delivery job instead of sending it directly.

    Edit your UserController and modify the create action as below:

    defcreate@user=User.new(user_params)[email protected]
    
      # UserMailer.welcome_email(@user).deliver_now  # Send email after user creationUserMailer.welcome_email(@user).deliver_later  # Send email later
      redirect_to @user, notice:"User was successfully created. A welcome email has been sent."else
      render :new, status::unprocessable_entityendend</pre>

    You can specify the wait parameter to deliver_later() method such as −

    UserMailer.welcome_email(user).deliver_later(wait:10.minutes)

    Or,

    UserMailer.welcome_email(user).deliver_later(wait_until:Time.tomorrow.noon)

    Callbacks

    The Active Job framework has certain hooks so that a defined logic can be triggered at various points during a job’s life cycle. These are the available callbacks for active jobs:

    CallbackDescription
    before_enqueueDefines a callback that will get called right before the job is enqueued.
    around_enqueueDefines a callback that will get called around the enqueuing of the job.
    after_enqueueDefines a callback that will get called right after the job is enqueued.
    before_performDefines a callback that will get called right before the job’s perform method is executed.
    around_performDefines a callback that will get called around the job’s perform method.
    after_performDefines a callback that will get called right after the job’s perform method has finished.

    Retrying or Discarding Failed Jobs

    It's possible to retry or discard a failed job by using retry_on or discard_on, respectively. If the configuration doesn't specify, a failed job will not be retried. Using retry_on or discard_on, respectively, you can attempt again after a failed job. And default retry_on is to 3 seconds and 5 attempts.

  • Forms

    The <form> . . </form> tag in HTML along with the form’s various input elements such textradioselect, etc. help you to create HTML forms.

    For example, a basic form to accept user input for a new book record, written in plain HTML would be like this:

    <form action="/books" method="post"><label for="title">Title:</label><input type="text" name="title" id="title"><label for="author">Author:</label><input type="text" name="author" id="author"><label for="price">Price:</label><input type="number" name="price" id="price"><input type="submit" value="Create Book"></form>

    Include this form element in new.html.erb script and visit http://localhost:3000/books/new in the browser to display the form −

    Ruby on Rails Forms

    If you provide a pure HTML form in a Rails application, it raises the following issues:

    • You must manually set action and method attributes.
    • No automatic field population as the values are lost if the form fails validation – especially if the form is used for update action.
    • You must manually handle CSRF protection.

    Rails Form Helpers

    Rails provides various form helpers to be used along with other helpers that generate the form elements like input types. These helpers when used instead of raw HTML forms has several advantages, making development faster, cleaner, and more maintainable.

    Following form helpers are available:

    • form_with
    • form_tag
    • form_for

    The form_with Helper

    The form_with helper is the recommended approach to render model-backed forms (linked to a database record).

    When called without arguments, it creates an HTML <form> tag with the value of the method attribute set to post and the value of the action attribute set to the current page.

    For example, assuming the current page is a home page at /home, the generated HTML will look like this:

    <%= form_with do|form|%>
      Put Form elements here
    <% end %>

    The corresponding HTMLscript will look like the following:

    <!--BEGIN app/views/books/new.html.erb --><form action="/books" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" 
       value="XolEv4UeO6RkT0yLuhmBKvYcPANvmW4Fj1CP07wvb2Bd4-WqCvoPt_R2Zo055uQTzM-FURYNLMibkcSbiGm5pg" autocomplete="off" />PutForm elements here
    </form><!--END app/views/books/index.html.erb -->

    Note that the form contains a hidden input element, authenticity_token, required for POST and PUT form submissions so as to prevent cross-site request forgery (CSRF) attacks. You can thus see how the form helpers automatically enable the security feature.

    The most preferred approach is to create a model-backed form y passing the model object as a parameter to form_with helper:

    <%= form_with model:@bookdo|f|%>
       Put various form elements here
    <% end %>

    Instead of the raw HTML form elements, you can use Rails helpers to render elements such as text fields, radio buttons, etc.

    The label Helper

    The label helper renders a HTML label.

    <%= form_with model: @book do |f| %>
      <%= f.label :title%>

    This is equivalent to the HTML label element:

    <label for=" title">Title</label>

    The text_field Helper

    The text_field helper renders a text input element, equivalent to <input type= “text”>

    <%= form_with model: @user do |f| %>
      <%= f.text_field :author%>
    <% end %>

    The corresponding HTML code would be −

    <input type="text" name="author" id="author">

    The text_area Helper

    The text_area helper generates a textarea element. Example:

    <%= form_with model: @user do |f| %>
      <%= f.textarea :detail%>
    <% end %>

    The radio_button Helper

    It’s the Rails helper for <input type= “radio”>. For example:

    <%= f.radio_button :format,"Gender"%>

    The check_box Helper

    The check_box helper is used to render a check box, as done by <input type=”checkbox”>.  For example:

    <%= f.check_box :available%>

    The submit Helper

    The submit helper outputs an <input type= “submit”> button that submits the form. Example:

    <%= f.submit "Create Book"%>

    Its equivalent HTML would be:

    <input type="submit" value="Create Book">

    We shall use these helpers to build a form that is used to enter book data.

    <%= form_with(model: @book, local: true) do |f| %>
       <div class="mb-3"><%= f.label :title, class: "form-label" %>
    
      &lt;%= f.text_field :title,class:"form-control", placeholder:"Enter book title"%&gt;
    </div><div class="mb-3"><%= f.label :author, class: "form-label" %>
      &lt;%= f.text_field :author,class:"form-control", placeholder:"Enter author's name"%&gt;
    </div><div class="mb-3"><%= f.label :price, class: "form-label" %>
      &lt;%= f.number_field :price,class:"form-control", step:"0.01", placeholder:"Enter book price"%&gt;
    </div><div class="d-grid"><%= f.submit "Create Book",class:"btn btn-primary"%> </div><%end%>

    The browser display in response to http://localhost:3000/books/new URL is:

    The submit Helper

    The form_tag Helper

    The form_tag helper also renders the HTML tag, but it is not linked to any ActiveRecord model. While the form_with helper uses the model object such as @book, the form_tag uses a URL path. You also must define the form submission method (POST/PUT) manually. The forms built with form_tag are generally used for setting search criteria or filters.

    The helpers for rendering form elements like text field are suffixed with _tag. For example, the text_field_tag helper generates text type input field.

    The following code renders a serach form with the use of form_tag helper

    <%= form_tag search_books_path, method: :get do %>
      <label>Search:</label>
      <%= text_field_tag :query, params[:query]%>
    
      <%= submit_tag "Search" %><%end%>

    The browser display in response to http://localhost:3000/books/new URL is:

    The form_tag Helper

    The form_tag Helper

    The form_tag helper also renders the HTML tag, but it is not linked to any ActiveRecord model. While the form_with helper uses the model object such as @book, the form_tag uses a URL path. You also must define the form submission method (POST/PUT) manually. The forms built with form_tag are generally used for setting search criteria or filters.

    The helpers for rendering form elements like text field are suffixed with _tag. For example, the text_field_tag helper generates text type input field.

    The following code renders a serach form with the use of form_tag helper

    <%= form_tag search_books_path, method: :get do %>
      <label>Search:</label>
      <%= text_field_tag :query, params[:query]%>
    
      <%= submit_tag "Search" %><%end%>

    The form_for Helper

    The form_for helper has now been deprecated since Rails 5 version, however, you can still use it. Here is an example:

    <%= form_for @book do |f| %>
      <%= f.text_field :title%>
      <%= f.text_field :author %><%= f.number_field :price %>
      <%= f.submit "Save Book"%>
    <% end %>

  • Scaffolding

    While you’re developing Rails applications, especially those which are mainly providing you with a simple interface to data in a database, it can often be useful to use the scaffold method.

    Scaffolding provides more than cheap demo thrills. Here are some benefits −

    • You can quickly get code in front of your users for feedback.
    • You are motivated by faster success.
    • You can learn how Rails works by looking at the generated code.
    • You can use scaffolding as a foundation to jump start your development.

    To understand scaffolding, let’s start by creating a new Rails application named cookbook. It will have database called cookbook and a table called recipes.

    Creating an Empty Rails Web Application

    Open a command window and navigate to where you want to create this cookbook web application and run the following command to create a complete project structure.

    rails new cookbook
    

    Rails uses SQLite as the default database. To specify other database type, use -d option. For example, the following command creates a Rail application with mysql as its backend database.

    rails new cookbook -d mysql
    

    Rails supports PostgreSql, Oracle, SQL Server and Maria DB databases also.

    By default, Rails includes importmaps for JavaScript, but you can choose a different frontend framework such as Webpack, Tailwind CSS, Bootstrap or ESBuild.

    If you are using RubyMine IDE, the new project wizard lets you choose the database and the frontend framework.

    Creating an Empty Rails Web Application

    Rails generates database.yml configuration file inside the config/ directory. It has the configuration for development as well as production environment.

    default:&default
      adapter: sqlite3
      pool:<%=ENV.fetch("RAILS_MAX_THREADS"){5}%>
      timeout:5000
    
    development:<<:*default
      database: storage/cookbook.sqlite3
    
    test:<<:*default
      database: storage/test.sqlite3
    production:
      primary:<<:*default
    
    database: storage/cookbook.sqlite3
    cache:<<:*default
    database: storage/production_cache.sqlite3
    migrations_paths: db/cache_migrate
    queue:<<:*default
    database: storage/production_queue.sqlite3
    migrations_paths: db/queue_migrate
    cable:<<:*default
    database: storage/production_cable.sqlite3
    migrations_paths: db/cable_migrate

    If you specify -d option with mysql as the database, database.yml file must contain the database credentials.

    development:
       adapter: mysql
       database: cookbook
       username: root
       password:[password]
       host: localhost
    	
    test:
       adapter: mysql
       database: cookbook
       username: root
       password:[password]
       host: localhost
    	
    production:
       adapter: mysql
       database: cookbook
       username: root
       password:[password]
       host: localhost
    

    If you prefer to use MySQL or PostgreSQL, you will need to run the command:

    rails db:create

    Generated Scaffold Code

    With the scaffold action, Rails generates all the code it needs dynamically. By running scaffold as a script, we can get all the code written to disk, where we can investigate it and then start tailoring it to our requirements.

    Run the scaffold generator to create a Recipe model with title (string) and instructions (text):

    rails g scaffold Recipe tittle:string instructions:text

    The command prompt terminal (terminal in Ubuntu) shows the following log as different files are created:

    Generated Scaffold Code

    This command creates:

    • Model: app/models/recipe.rb
    • Migration: db/migrate/ rb
    • Controller: app/controllers/recipes_controller.rb
    • Views: app/views/recipes/
    • Routes: Updates config/routes.rb

    Run the Migration

    You can use Rails Migrations to create and maintain tables. Apply the migration to create the recipes table in MySQL:

    rake db:migrateRAILS_ENV=development
    

    The command terminal shows the following log:

    rake db:migrateRAILS_ENV=development
    ==20250220120618CreateRecipes: migrating ====================================-- create_table(:recipes)->0.0026s
    ==20250220120618CreateRecipes: migrated (0.0035s)===========================

    This will create the recipes table with the following structure:

    CREATETABLE recipes (
    
    id           INTEGERPRIMARYKEY AUTOINCREMENT
                              NOTNULL,
    tittle       VARCHAR,
    instructions TEXT,
    created_at   DATETIME(6)NOTNULL,
    updated_at   DATETIME(6)NOTNULL);</pre>

    The Controller

    Let's look at the code behind the controller. This code is generated by the scaffold generator. If you open app/controllers/recipes_controller.rb, then you will find something as follows

    classRecipesController<ApplicationController
      before_action :set_recipe, only:%i[ show edit update destroy ]# GET /recipes or /recipes.jsondefindex@recipes=Recipe.all
      end# GET /recipes/1 or /recipes/1.jsondefshowend# GET /recipes/newdefnew@recipe=Recipe.newend# GET /recipes/1/editdefeditend# POST /recipes or /recipes.jsondefcreate@recipe=Recipe.new(recipe_params)
    
    
    respond_to do|format|[email protected]
        format.html { redirect_to @recipe, notice:"Recipe was successfully created."}
        format.json { render :show, status::created, location:@recipe}else
        format.html { render :new, status::unprocessable_entity}
        format.json { render json:@recipe.errors, status::unprocessable_entity}endendend# PATCH/PUT /recipes/1 or /recipes/1.jsondefupdate
    respond_to do|format|[email protected](recipe_params)
        format.html { redirect_to @recipe, notice:"Recipe was successfully updated."}
        format.json { render :show, status::ok, location:@recipe}else
        format.html { render :edit, status::unprocessable_entity}
        format.json { render json:@recipe.errors, status::unprocessable_entity}endendend# DELETE /recipes/1 or /recipes/[email protected]!
    respond_to do|format|
      format.html { redirect_to recipes_path, status::see_other, notice:"Recipe was successfully destroyed."}
      format.json { head :no_content}endendprivate# Use callbacks to share common setup or constraints between actions.defset_recipe@recipe=Recipe.find(params.expect(:id))end# Only allow a list of trusted parameters through.defrecipe_params
      params.expect(recipe:[:tittle,:instructions])endend</pre>

    When the user of a Rails application selects an action, e.g. "Show" - the controller will execute any code in the appropriate section - "def show" - and then by default will render a template of the same name - "show.html.erb". This default behavior can be overwritten.

    The controller uses ActiveRecord methods such as find, find_all, new, save, update_attributes, and destroy to move data to and from the database tables. Note that you do not have to write any SQL statements, rails will take care of it automatically.

    This single line of code will bring the database table to life. It will provide with a simple interface to your data, and ways of −

    • Creating new entries
    • Editing current entries
    • Viewing current entries
    • Destroying current entries

    When creating or editing an entry, scaffold will do all the hard work like form generation and handling for you, and will even provide clever form generation, supporting the following types of inputs −

    • Simple text strings
    • Text areas (or large blocks of text)
    • Date selectors
    • Date-time selectors

    Now, go to the cookbook directory and run the Web Server using the following command −

    rails server
    

    Now, open a browser and navigate to http://127.0.0.1:3000/recipes/new. This will provide you a screen to create new entries in the recipes table. A screenshot is shown below

    The Controller

    Once you press the Create button to create a new recipe, your record is added into the recipes table and it shows the following result

    The Controller 1

    You can see the option to edit, show, and destroy the records. So, play around with these options.

    The Controller 2

    Enhancing the Model

    Rails gives you a lot of error handling for free. To understand this, add some validation rules to the empty recipe model −

    Modify app/models/recipe.rb as follows and then test your application −

    classRecipe<ActiveRecord::Base
       validates_length_of :title,:within=>1..20
       validates_uniqueness_of :title,:message=>"already exists"end

    These entries will give automatic checking.

    • validates_length_of − the field is not blank and not too long.
    • validates_uniqueness_of − duplicate values are trapped. Instead of the default Rails error message, we have given a custom message here.

    The Views

    All the views and corresponding all the controller methods are created by scaffold command and they are available in the app/views/recipes directory.

    How Scaffolding is Different?

    Although we can manually create the methods to list, show, delete and create data etc., but scaffolding does that job automatically.

  • Layouts

    When Rails renders a view as a response, it does so by combining the view with the current layout. A layout defines the surroundings of an HTML page. It’s the place to define a common look and feel of your final output.

    By default, Rails uses the app/views/layouts/application.html.erb file as the main layout. It is created when you create a new ails application.

    If you create a library application with rails new library command, its main layout code would be as follows:

    <!DOCTYPE html><html><head><title><%= content_for(:title) || "library" %></title><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="mobile-web-app-capable" content="yes">
    
    &lt;%= csrf_meta_tags %&gt;
    &lt;%= csp_meta_tag %&gt;
    &lt;%= yield :head %&gt;
    &lt;%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %&gt;
    &lt;%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %&gt;
    &lt;link rel="icon" href="/icon.png" type="image/png"&gt;&lt;link rel="icon" href="/icon.svg" type="image/svg+xml"&gt;&lt;link rel="apple-touch-icon" href="/icon.png"&gt;
    &lt;%# Includes all stylesheet files in app/assets/stylesheets %&gt;
    &lt;%= stylesheet_link_tag :app, "data-turbo-track": "reload" %&gt;
    &lt;%= javascript_importmap_tags %&gt;
    </head><body>
    &lt;%= yield %&gt;
    </body></html>

    The main aspects of this layout code are:

    • Asset tags
    • yield and content_for
    • Partials

    Asset Tags

    These tags generate HTML to create links to different resources such as JavaScript and CSS scripts, images etc.

    The stylesheet_link_tag helper returns an HTML <link> tag for each source provided. In the above code, the statement

    <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
    

    generates a link to /assets/stylesheets/app.css

    Similarly, the statement such as,

    <%= javascript_include_tag "main"%>

    Outputs a script tag as follows:

    <script src='app/assets/javascripts/main.js'></script>

    The yield Tag

    The application.html.erb file acts as a base template used by the individual view templates. For example, the index action in the BooksController renders the index.html.erb view. The tag <%= yield %> inside application.html.erb marks a section where content from the view should be inserted.

    This can be verified by looking at the log generated on the command terminal when you start the server and visit the index view (http://localhost:3000/books/)

    StartedGET"/books"for::1 at 2025-03-2500:11:13+0530Processing by BooksController#index as HTMLRendering layout layouts/application.html.erb
      Rendering books/index.html.erb within layouts/application
      BookLoad(4.3ms)SELECT"books".*FROM"books"/*action='index',application='Controllerdemo',controller='books'*/
      ↳ app/views/books/index.html.erb:1Rendered books/index.html.erb within layouts/application (Duration:14.6ms |GC:0.0ms)Rendered layout layouts/application.html.erb (Duration:519.7ms |GC:0.3ms)Completed200OKin2448ms (Views:518.6ms |ActiveRecord:4.3ms (1 query,0 cached)|GC:0.3ms)

    Rails first renders the application layout and then renders the index.html.erb inside it. Thus the yield tag is a place holder for the output of the view to be inserted.

    Let us assume that the Rails application has a BooksController with index and show actions, A book model that has been migrated and a few book records already entered.

    classBooksController<ApplicationControllerdefindex@books=Book.all
      end

    The index action renders the index view (index.html.erb):

    <% if @books.blank? %>
    <p>There are not any books currently in the system.</p>
    <% else %>
    <p>These are the current books in our system</p><ul id = "books">
       <% @books.each do |c| %>
       <li><%= link_to c.title, {:action => 'show', :id => c.id} -%></li>
       <% end %>
    </ul>
    
    <% end %>
    <p><%= link_to "Add new Book", {:action => 'new' }%></p>

    The following figure shows the output of index view when the default application layout is used.

    The yield Tag

    Changing the Default Layout

    Let us now change the default layout. Save the following code to app\views\layouts\standard.html.erb.

    <!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns ="http://www.w3.org/1999/xhtml"><head><meta http-equiv ="Content-Type" content ="text/html; charset = iso-8859-1"/><meta http-equiv ="Content-Language" content ="en-us"/><title>LibraryInfoSystem</title></head><body id ="library"><div id ="container"><div id ="header"><h1>LibraryInfoSystem</h1><h3>Library powered by Ruby on Rails</h3></div><div id ="content"><%= yield -%>
    
         &lt;/div&gt;
         &lt;div id ="sidebar"&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</pre>

    You let the controllers know what template to use by the name of the file, so following a same naming scheme is advised. Now open books_controller.rb and add layout command to specify the layout to be used.

    classBooksController<ApplicationController
      layout "standard"defindex@books=Book.all
      end

    It instructs the controller that we want to use a layout available in the standard.html.erb file. Now try browsing books that will produce the following screen. Restart the server and visit the index view. The browser shows the following output.

    Changing the Default Layout

    The command terminal log also confirms that the standard layout is in use.

    Rendered books/index.html.erb within layouts/standard (Duration:6.9ms |GC:0.0ms)Rendered layout layouts/standard.html.erb (Duration:9.0ms |GC:0.0ms)

    Adding the Style Sheet

    Till now, we have not created any style sheet, so Rails is using the default style sheet. Now let's create a new file called style.css and save it in /public/stylesheets. Add the following code to this file.

    body {
    
    font-family: Helvetica, Geneva, Arial, sans-serif;
    font-size: small;
    color: #000;
    background-color: #fff;
    } a:link, a:active, a:visited {
    color: #CD0000;
    } input {
    margin-bottom: 5px;
    } p {
    line-height: 150%;
    } div#container {
    width: 760px;
    margin: 0 auto;
    } div#header {
    text-align: center;
    padding-bottom: 15px;
    } div#content {
    float: left;
    width: 450px;
    padding: 10px;
    } div#content h3 {
    margin-top: 15px;
    } ul#books {
    list-style-type: none;
    } ul#books li {
    line-height: 140%;
    } div#sidebar {
    width: 200px;
    margin-left: 480px;
    } ul#subjects {
    width: 700px;
    text-align: center;
    padding: 5px;
    background-color: #ececec;
    border: 1px solid #ccc;
    margin-bottom: 20px;
    } ul#subjects li {
    display: inline;
    padding-left: 5px;
    }

    Now refresh your browser and see the difference −

    Adding the Style Sheet

    You can also create a layout with multiple yielding regions:

    <html><head>
    
    &lt;%= yield :head %&gt;
    </head><body>
    &lt;%= yield %&gt;
    </body></html>

    The main body of the view will always render into the unnamed yield. To render content into a named yield, call the content_for method with the same argument as the named yield.

    Using Partials

    Rails supports Partial templates - usually just called "partials" are reusable components stored in files prefixed with an underscore (_).

    Let us add a navbar to the standard layout. For this purpose, first save the following HTML as _navbar.html.erb in app\views\books folder

    <nav><ul class="horizontal-navbar"><li><a href="/">Home</a></li><li><a href="/show">Show</a></li></ul></nav>

    To render a partial as part of a view, you use the render method inside the standard layout. Here, the navbar is to be displayed on the top, so add the following stamen in the <head> section.

    <%= render "navbar" %>
    

    This will render a file named _navbar.html.erb at that point within the view being rendered. Note the leading underscore character: partials are named with a leading underscore to distinguish them from regular views, even though they are referred to without the underscore.

    You may have to update the style.css to include the navbar styles.

    .horizontal-navbar {
       list-style-type: none;
       padding: 0;
       margin: 0;
       display: flex;
     }
     
     .horizontal-navbar li {
       margin-right: 20px;
     }
     
     .horizontal-navbar li a {
       text-decoration: none;
       color: black;
     }
    

    Save the changes and refresh the browser. The index view now displays the navbar at the top as a result of including the partial template.

    Using Partials
  • Rendering

    In Rails, the controller is responsible for processing the incoming request and creating the response to be sent back to the client.

    The controller uses mainly the following three ways to create the response

    • render
    • render_to
    • head

    The render Method

    By default, controllers in Rails automatically render views with names that correspond to valid routes. The render method is often called implicitly.

    If you have a BooksController class with index action as defined below:

    classBooksController<ApplicationControllerdefindex@books=Book.all
      endend

    You also have the routes defined as:

    resources :books

    And a view file index.html.erb is also in place.

    There is no explicit call to render at the end of the index action, as Rails follows the principle “convention over configuration”, according to which you do not explicitly render something at the end of a controller action, Rails automatically looks for the action_name.html.erb template in the controller’s view path and render it.

    Here, Rails automatically looks for a view template in app/views/books/index.html.erb and renders it.

    However, if you want to override the default behaviour and render a different template, partial, or even JSON, you can explicitly call render.

    classBooksController<ApplicationControllerdefindex@book=Book.all
    
    render 'list'endend</pre>

    This will render app/views/books/list.html.erb instead of index.html.erb.

    Incidentally, there’s also a render_to_string method. It takes exactly the same options as render, but it returns a string instead of sending a response back to the browser.

    You can also send an HTML string back to the browser by using the :html option to render method. This is especially useful when you're rendering a small snippet of HTML code instead of the entire template.

    render html:"<h1>Welcome to the Books Section</h1>".html_safe
    

    The .html_safe clause is required to prevent Rails from escaping HTML.

    Rails has built-in support for converting objects to JSON and rendering that JSON back to the browser:

    render json:@book

    Likewise, Rails also has built-in support for converting objects to XML and rendering that XML back to the caller:

    render xml:@book

    In both the cases, you don't need to call to_json or to_xml on the object that you want to render. If you use the :xml option, render will automatically call to_xml for you. Similarly, if you use the :json option, render will automatically call to_json for you.

    Rendering JavaScript is also possible with the render js method.

    render js:"alert('Hello World');"

    The :plain option lets you can send plain text - with no markup at all - back to the browser.

    render plain:"OK"

    Note: The text is rendered without using the current layout. To put the text into the current layout, you need to add the layout: true option and use the .text.erb extension for the layout file.

    The redirect_to Method

    The redirect_to method does something completely different: it tells the browser to send a new request for a different URL. This method needs to be explicitly called.

    The key difference between render vs. redirect_to methods is that – "while the render method returns a response directly (HTML, JSON, etc.), the redirect_to method sends an HTTP redirect to another URL."

    classBooksController<ApplicationControllerdefshow@book=Book.find(params[:id])
    
    redirect_to books_path
    endend

    This changes the URL to /books and performs a new request.

    You can use redirect_back to return the user to the page they just came from. Note that these methods do not halt and return immediately from method execution, but simply set HTTP responses.

    Rails uses returns the status code 302, which indicates a temporary redirect, when you call redirect_to. To use a different status code, such as 301, (it stands for a permanent redirect) you can use the :status option:

    redirect_to books_path, status:301

    The head Method

    The head method can be used to send responses with only headers to the browser. The head method optionally accepts a number representing an HTTP status code. For example, you can return only an error header:

    head :bad_request

    Or you can use other HTTP headers to convey other information:

    head :created, location: book_path(@book)

    The options argument is interpreted as a hash of header names and values.

  • Views

    Rails View is an ERB program that shares data with controllers through mutually accessible variables. Rails uses ERB (Embedded Ruby) as its default template engine to interpret and process .html.erb files.

    If you look in the app/views directory of any Rails application, you will see one subdirectory for each of the controllers. Each of these subdirectories was created automatically when the same-named controller was created with the generate script.

    Rails lets you know that you need to create the view file for each new method. Each method you define in the controller needs to have a corresponding erb file, with the same name as the action (method), to display the data that the method is collecting.

    Assume that a controller is created with the following command:

    rails generate controller Book

    This will create the controller (app/controllers/books_controller.rb). If you define an action inside this controller:

    defindexend

    You need to create the view file as app/views/books/index.html.erb.

    ERB (Embedded Ruby) allows you to write Ruby code inside HTML using special tags:

    ERB SyntaxPurpose
    <% … %>Executes Ruby code (no output)
    <%= … %>Executes and outputs the result
    <%# … %>Comment (ignored in output)

    So, let’s create view files for all the methods we have defined in the books_controller.rb. While executing these views, simultaneously check these actions are applicable into the database or not.

    Creating View File for create Action

    Modify the books_controller.rb file to add following action methods:

    defnew@book=Book.newend

    Here, @book is an instance variable. The new action initializes a new Book and used in app/views/books/new.html.erb to build the form and enter Book details. (We shall see how to create the form).

    Also define create action to handle the form submission. The form data is submitted to this action which calls save method of the book instance and pushes a flash message indicating the success.

    defcreate@book=Book.new(book_params)[email protected]
    
      flash[:notice]="Book was successfully created."
      redirect_to @book# Redirects to show action (book details)else
      render :new, status::unprocessable_entityendend</pre>

    Rails form Helpers

    Rails recommends using its helpers instead of using the normal HTML elements to build the content tags and form elements. The following code in new.html.erb uses form helpers like form_with, form.label, form.text_field etc. to render a blank Book form.

    <%= form_with(model: @book, local: true, html: { class: 'book-form' }) do |form| %>
    
      <div class="field"><%= form.label :title, class: 'form-label' %>
    
    &lt;%= f.text_field :title,class:"form-control", placeholder:"Enter book title"%&gt;
    </div><div class="field"><%= form.label :author, class: 'form-label' %>
    &lt;%= f.text_field :author,class:"form-control", placeholder:"Enter author's name"%&gt;
    </div><div class="field"><%= form.label :price, class: 'form-label' %>
    &lt;%= f.number_field :price,class:"form-control", step:"0.01", placeholder:"Enter book price"%&gt;
    </div><div class="actions"><%= form.submit CreateBook', class: 'form-submit' %>

    Some of the Rails view helpers are as follows:

    • form_with − Generates a form based on a Model
    • form_tag − Creates a form without a model

    Following helpers are used inside the form helper form_with, for example −

    <%= form_with(model: @book, local: true) do |f| %>
      <%= f.label :title%>
      <%= f.text_field :title %><%= f.submit "Save"%>
    <% end %>

    Form element helpers

    • label : renders a HTML label
    • text_field : renders a text input element, equivalent to <input type= "text">
    • text_area : generates a textarea element
    • radio_button : Rails helper for <input type= "radio">
    • check_box : used to render a check box, as done by <input type="checkbox">
    • submit : outputs an <input type= "submit"> button that submits the form.

    URL & Link Helpers

    • link_to : creates a hyperlink, equivalent to href
    • button_to : generates a form-based button
    • image_tag : Inserts an image, similar to img src

    Make sure that the config/routes.rb file is present with following resources statement.

    resources :books

    Start the Rails server

    rails server
    

    Add New Book

    Visit http://localhost:3000/books/new URL to display the form.

    Add New Book

    Enter data for a new book and click the Create Book button.

    Creating View File for list of books

    The index action in the BooksController stores all the objects in the Book model in @books variable.

    defindex@books=Book.all
    end

    This will need the index.html.erb file. The book data is displayed in a HTML table. In addition to the columns title, author and price, we use link_to helper to hyperlink buttons for show, edit and delete actions are provided in each row.

    We also use the flash[:notice] helper to extract the flash messages pushed by any of the earlier actions.

    <div class="container"><h2 class="text-center">All Books</h2><!-- Flash Messages -->
      <% if flash[:notice] %>
    
    &lt;p class="notice"&gt;&lt;%= flash[:notice] %&gt;&lt;/p&gt;
    <% end %> <!-- Books Table --><table class="table table-bordered table-striped"><thead class="table-dark"><tr><th>ID</th><th>Title</th><th>Author</th><th>Price</th><th colspan=3>Actions</th></tr></thead><tbody>
      &lt;% @books.each do |book| %&gt;
        &lt;tr&gt;&lt;td&gt;&lt;%= book.id %&gt;&lt;/td&gt;&lt;td&gt;&lt;%= book.title %&gt;&lt;/td&gt;&lt;td&gt;&lt;%= book.author %&gt;&lt;/td&gt;&lt;td&gt;₹&lt;%= book.price %&gt;&lt;/td&gt;&lt;td&gt;
            &lt;%= link_to "Show", book_path(book), class: "btn btn-info btn-sm me-2" %&gt;
            &lt;/td&gt;&lt;td&gt;
            &lt;%= link_to "Edit", edit_book_path(book), class: "btn btn-warning btn-sm me-2" %&gt;
            &lt;/td&gt;&lt;td&gt;
            &lt;%= link_to "Delete", book_path(book), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-danger btn-sm" %&gt;
          &lt;/td&gt;&lt;/tr&gt;
      &lt;% end %&gt;
    &lt;/tbody&gt;&lt;/table&gt;&lt;!-- Button to Add New Book --&gt;
    <%= link_to "Add New Book", new_book_path, class: "btn btn-primary mt-3" %> </div>

    The index view displays the list of books as follows −

    Creating View File for list of books

    Creating View File for show Method

    The show action in booksController fetches a book of the ID passed to it as the parameter

    defshow@book=Book.find(params[:id])# Fetch book by IDend

    The corresponding show.html.erb view template is as follows:

    <div class="container"><h2 class="text-center">Book Details</h2><div class="card"><div class="card-body"><h4 class="card-title"><%= @book.title %></h4><p><strong>Author:</strong> <%= @book.author %></p><p><strong>Price:</strong> ₹<%= @book.price %></p></div></div>
    
      <%= link_to "Back to Books", books_path, class: "btn btn-secondary mt-3" %>
    </div>

    Click on the Show button of inside the desired row to display the detailed view of a book.

    Creating View File for show Method

    Creating View File for edit Method

    Add the edit action in the BooksController to fetch the specified book object.

    defedit@book=Book.find(params[:id])end

    This will render the edit.html.erb view, which we shall write later.

    Also, add the update action to process the data submitted by the edit template.

    defupdate@book=Book.find(params[:id])[email protected](book_params)
    
      redirect_to @book, notice:"Book was successfully updated."else
      render :edit, status::unprocessable_entityendend</pre>

    The edit.html.erb code is similar to new.html.erb, except that the fields are populated with the data of the book to be updated.

    <div class="container"><h2 class="text-center">Edit Book</h2>
    
      <%= form_with model: @book, local: true do |form| %>
    
    &lt;div class="form-group"&gt;
      &lt;%= form.label :title %&gt;
      &lt;%= form.text_field :title, class: "form-control" %&gt;
    &lt;/div&gt;&lt;div class="form-group"&gt;
      &lt;%= form.label :author %&gt;
      &lt;%= form.text_field :author, class: "form-control" %&gt;
    &lt;/div&gt;&lt;div class="form-group"&gt;
      &lt;%= form.label :price %&gt;
      &lt;%= form.number_field :price, class: "form-control" %&gt;
    &lt;/div&gt;
    &lt;%= form.submit "Update Book", class: "btn btn-success mt-3" %&gt;
    <% end %> <%= link_to "Cancel", book_path(@book), class: "btn btn-secondary mt-3" %> </div>

    While on the index page that shows the list of books, click on the edit button to update the details. Change the desired data and click on Update book button. The browser returns the list of books with a flash message “Book was successfully Updated”

    Creating View File for edit Method

    Finally, the delete action in the BooksController calls the destroy() method on the selected Book object and removes from the book model.

    defdelete@book=Book.find(params[:id])@book.destroy
    
    redirect_to books_path, notice:"Book was successfully deleted."end</pre>

    What is Next?

    Hope now you are feeling comfortable with all the operations of Rails.

    The next chapter explains how to use Layouts to put your data in a better way. We will show you how to use CSS in your Rails applications.

  • Routes

    The routing module provides URL rewriting in native Ruby. It’s a way to redirect incoming requests to controllers and actions. It replaces the mod_rewrite rules. Best of all, Rails’ Routing works with any web server. Routes are defined in app/config/routes.rb.

    A route is the part of the URL that determines how an incoming HTTP request is directed to the appropriate controller and action for processing. It tells Rails which controller and action should respond to a request.

    Think of creating routes as drawing a map for your requests. The map tells them where to go based on some predefined pattern −

    Rails.application.routes.draw doPattern1 tells some request to go to one place
       Pattern2 tell them to go to another
       ...end

    When Rails sees a request that matches any of the patterns, it will send the request to the corresponding controller and the appropriate action inside of that controller.

    There are 4 common actions you will generally need for a resource: CreateReadUpdateDelete (CRUD). This translates to 7 typical routes:

    ActionHTTP VerbPathPurpose
    indexGET/booksList all records
    showGET/books/:idShow a single record
    newGET/books/newDisplay a form for a new record
    createPOST/booksSave a new record to the database
    editGET/books/:id/editDisplay a form to edit a record
    updatePATCH/PUT/books/:idUpdate an existing record
    destroyDELETE/books/:idDelete a record

    Typing out these routes every time is redundant, so Rails provides a shortcut for defining them. To create all of the same CRUD routes, replace the above routes with this single line.

    Example

    Let us consider our library management application contains a controller called BookController. We have to define the routes for those actions which are defined as methods in the BookController class.

    Open routes.rb file in library/config/ directory and edit it with the following content.

    Rails.application.routes.draw do
      resources :booksend

    If you decide to define only a certain routes instead of all the default routes, you can put the required routes in a list.

    Rails.application.routes.draw do
      resources :books, only:%i[index show create]end

    You may also define the routes explicitly by mentioning the respective HTTP verbs

    Rails.application.routes.draw do
      get 'books/'
      get 'books/show'
      post 'books/create'end

    This works because Rails automatically maps get ‘books/index’ to BooksController#index.

    If the path does not directly match the controller#action, you must specify to: explicitly:

    get 'all-books', to:'books#index'# Custom URL: /all-books
    get 'book-view/:id', to:'books#show'# Custom URL: /book-view/:id

    If your application has multiple models (e.g., Book and Employee), you should have separate resources statements for each model in config/routes.rb.

    Rails.application.routes.draw do
      resources :books
      resources :employeesend

    The routes.rb file defines the actions available in the applications and the type of action such as get, post, and patch.

    Use the following command to list all your defined routes, which are useful for tracking down routing problems in your application, or giving you a good overview of the URLs in an application you’re trying to get familiar with.

    rails routes
    

    In the older version of Ruby on Rails (before version 5), you would use:

    rake routes
    

    What is Next?

    Next, we will create the code to generate screens to display data and to take input from the user.

  • Authentication

    The library application used in this tutorial has the CRUD actions to add, edit, and delete book objects. However, these actions are accessible to anyone, which isn’t safe. Let us add a security layer to the application, so that only authenticated users get the access.

    Authentication Generator

    Starting with Rails version 8.0, a default authentication generator is included to streamline the process of securing your application by allowing access only to verified users.

    From the command terminal (windows) or Linux terminal, run the following command:

    rails generate authentication
    

    It generates the following models −

    app/models/session.rb
    app/models/user.rb
    app/models/current.rb
    

    Rails also generates the following controllers −

    app/controllers/sessions_controller.rb
    app/controllers/passwords_controller.rb
    

    And these views −

    app/views/passwords/new.html.erb
    app/views/passwords/edit.html.erb
    app/views/sessions/new.html.erb
    

    Next, you need to run the database migration to create the respective tables necessary for the authentication system:

    rails db:migrate

    Now, if you try to visit any route, Rails asks for the user to login with email and password.

    How the Authentication Works?

    Let us create a user object first. Open the Rails console and run the following command:

    User.create! email_address:"[email protected]", password:"a1b2c3", password_confirmation:"a1b2c3"

    Assuming that you have already created the Bookscontroller class, defined an index action in it and provided the corresponding index.html.erb file.

    Run the Rails server and visit http://localhost:3000/ upon which the browser displays this login page:

    How the Authentication Works?

    Rails authenticates the entered email address and password registered with it and automatically redirects the browser to the index view.

    By default, the Rails authentication generator will restrict all pages to authenticated users only. However, if you want some of the pages to be accessible without authentication, such as guest visitors, allow_unauthenticated_access property can be used for the purpose.

    How to Allow Guest Users

    To allow guests to view products, we can allow unauthenticated access in our controller.

    classBooksController<ApplicationController
      allow_unauthenticated_access only:%i[ index show ]# ...end

    Rails also provides the before_action that runs before executing a specific controller action. It’s mainly used for tasks like authentication, setting up variables, or checking permissions.

    classApplicationController<ActionController::Base
      before_action :set_messagedefindexend
    • The before_action callback helps avoid redundant code (e.g., authentication checks in every action). Use only: and except: inside the controller to control execution.
    • There is also an after_action callback, intended to run after the action runs, and the round_action callback that wraps before & after the logic.

    This built-in authentication system works well for small applications. You can use Devise Authentication by using Devise (a popular authentication gem). To generate authentication with Devise:

    rails generate devise:install
    rails generate devise User# Generates User model with authentication
    rails db:migrate

    You can also use jwt for token-based authentication.