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.
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.
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_texts, active_storage_blobs, active_storage_attachments, active_storage_variant_records)
The application.js file shows that trix and actiontext support has been added.
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? %>
<div style="color: red"><h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% post.errors.each do |error| %>
<li><%= error.full_message %></li><%end%>
</ul></div><%end%>
That’s it. Save all the changes and run the server. The /posts/new route provides a trix editor for the content field.
Click on the Create Post. The application displays the confirmation of the post creation with the help of show view.
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.).
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.
You now need to install a queuing service to handle the background jobs. We have a variety of background queuing libraries such as delayed jobs, sidekiq, rescue, 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.
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.
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:
# 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 −
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:
Callback
Description
before_enqueue
Defines a callback that will get called right before the job is enqueued.
around_enqueue
Defines a callback that will get called around the enqueuing of the job.
after_enqueue
Defines a callback that will get called right after the job is enqueued.
before_perform
Defines a callback that will get called right before the jobâs perform method is executed.
around_perform
Defines a callback that will get called around the jobâs perform method.
after_perform
Defines 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.
Include this form element in new.html.erb script and visit http://localhost:3000/books/new in the browser to display the form −
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.
The browser display in response to http://localhost:3000/books/new URL is:
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
The browser display in response to http://localhost:3000/books/new URL is:
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
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.
Rails generates database.yml configuration file inside the config/ directory. It has the configuration for development as well as production environment.
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:
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:
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|
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
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
You can see the option to edit, show, and destroy the records. So, play around with these options.
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 −
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:
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 bookmodel 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.
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 -%>
</div>
<div id ="sidebar"></div></div></body></html></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.
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.
You can also create a layout with multiple yielding regions:
<html><head>
<%= yield :head %>
</head><body>
<%= yield %>
</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
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.
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.
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 renderjs 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."
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.
A 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 Syntax
Purpose
<% … %>
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.
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.
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.
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.
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â
Finally, the delete action in the BooksController calls the destroy() method on the selected Book object and removes from the book model.
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: Create, Read, Update, Delete (CRUD). This translates to 7 typical routes:
Action
HTTP Verb
Path
Purpose
index
GET
/books
List all records
show
GET
/books/:id
Show a single record
new
GET
/books/new
Display a form for a new record
create
POST
/books
Save a new record to the database
edit
GET
/books/:id/edit
Display a form to edit a record
update
PATCH/PUT
/books/:id
Update an existing record
destroy
DELETE
/books/:id
Delete 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.
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:
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:
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.
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.