Rails
Learning Rails was very very difficult for me. It required me to learn lot of concepts like Model View Controller (MVC) and other things. I failed many times before I could learn enough to call myself a Rails developer.
I would compare Rails with a rail way system. You need a lot to get it running, one must lay tracks, power lines, the infrastructure and so on, but once done, you have got a very efficient system of transport at your disposal.
Programming using PHP and other languages is like walking, you can start walking right now, but imagine how long it would take to walk from Chennai to Delhi? Would you prefer to walk or take a train?
You need to invest time and energy to learn Rails, but once done, you will have the power to create web apps @ lightning speed.
Where Rails is Effective?
Though you can build a simple 5 page website with Rails, Rails is not good for for that. Rails is good for building medium to large web projects that relies on Data Base (RDMS) to get its data, and to get user input and store it in Data Base.
Usually you would see use of Rails in apps which need be got to market fast, as Rails has got lot of batteries included. It has got libraries for data manipulation, like defining tables, adding modifying and removing columns from them. It has got way to wrap Ruby classes around tables, specifying relationship between those classes. It has got components to specify how your HTML page should be built and rendered, and it has got ways to manage your assets like images, Javascript’s and CSS etc. I would have left one or two here and there. In all Rails is a huge library that helps you to build web pages very fast.
Rails today is used for building SAAS app, and/or an app that provides JSON backend. It’s usually used by small teams to build products that compete with big companies that employ tens of people.
Apart from building apps, Rails has also got ways to test the web app you are building. by writing automated tests, you would minimize the errors you will create in the future. you can refractor code with confidence and hence maintain the app top notch.
There are services like Heroku that would help you to deploy Rails app quickly thus reducing your IT cost and time to market.
In short if you want to build a fairly complex to advanced RDBMS driven web app, Rails is the right choice for you.
Getting this book
One can get this book here https://rails-7.gitlab.io
Once can get code for this book here https://gitlab.com/rails-7/code
Hardware Requirements
Almost all web apps today are deployed on GNU/Linux machines for stability. So its better to learn Rails on a GNU/Linux system. I have deployed all my Rails app on Ubuntu, so its better to get a Ubuntu laptop to learn rails. Make sure it has got 8GB+ of RAM.
Getting Help
One of the strong features of popular free software language is that one would find plenty of help. One of the advantage of Ruby programming language is that many people like to code with it, and many people would like to offer help to people who code with it. In this section you will find places where you can seek help.
Ruby Mailing List
One of the best places to see help for Ruby programming language is the Ruby mailing list. Visit https://www.ruby-lang.org/en/community/mailing-lists/, scroll down to see a form like this:
Fill in your email and submit it to join the mailing list.
Rails Forum
Ruby on Rails has a discussion forum, one can find it here https://discuss.rubyonrails.org/, register and try to answer people who have doubts, and ask questions about Rails here.
Stack Overflow
If you are a programmer, you would have heard about stack overflow https://stackoerflow.com, you can ask your doubts there too. Personally I would prefer Ruby mailing list and Ruby on Rails forum.
Reddit has a passionate Ruby community https://www.reddit.com/r/ruby/ and Rails community https://www.reddit.com/r/rails/, you can discuss and ask doubts here too.
Ruby & Rails API
You might get doubt, or find a way to do something short using Ruby or Rails, both Ruby language and Rails framework has got a rich set of API. One can find Ruby API here https://ruby-doc.org/ and Rails api here https://api.rubyonrails.org/. These links will be useful when you are well acquainted with Ruby and Rails.
Prerequisite
I don’t think one can start with Rails just like that. In fact I would say that one already has to know web development to get comfortable with Rails. This section explains what you need to know to get started with Rails.
Writing Code
One should know to write code if you want to start to learn Rails. Don’t think that by not even knowing how to write code, and not having prior experience of writing code, you can somehow get started with Rails. It does not work.
GNU/Linux
You must have knowledge of GNU/Linux, have a good GNU/Linux system, and try to learn about it. You can learn GNU/Linux from this excellent website https://linuxjourney.com
HTML & CSS
You need to know how to create web pages to start learning Rails. You need to know about HTML and CSS, one can learn about HTML here https://www.w3schools.com/html/ and CSS here https://www.w3schools.com/CSS/
JavaScript
JavaScript is the only practical language that works on browser now. There is another thing called web assembly, but for today it’s just a curiosity. You can learn JavaScript here https://www.w3schools.com/js/, or get this book JavaScript: The Definitive Guide here https://www.amazon.in/dp/B088P9Q6BB/
SQL
Rails is used to create webpages with Database (DB) backend. For that you need to know SQL, you may learn it here https://www.w3schools.com/sql/
I would also one to install PostgreSQL https://www.w3schools.com/sql/ on ones system and practice it.
Ruby
Finally, Ruby programming language is the hero of Ruby on Rails. Rails is built using this language. I would recommend my book I Love Ruby https://i-love-ruby.gitlab.io/ to learn it.
git
Today almost no one codes in isolation, you need to work with some one, you may make a big mistake in your code which need to be reversed. git is tool initially created by Linus Tovarlds, the same guy who created GNU/Linux, and its the version control tool for programmers. You can learn git here https://www.tutorialspoint.com/git/index.htm
Installing Rails
First check if you have Ruby installed. In your terminal check it using ruby -v
as shown.
$ ruby -v
ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin21]
Make sure that you have installed Ruby using rvm https://rvm.io/ or other similar version manager.
Now let’s install Rails. If you are familiar with Ruby, they you would have heard about Ruby Gems https://rubygems.org/, which are nothing but distributable Ruby libraries zipped into a file. It’s centrally available in https://rubygems.org/ for the world to use. You can get the rails gem by typing gem install rails
in terminal.
this would generate lot of output as shown below:
$ gem install rails
Fetching thor-1.2.1.gem
Fetching method_source-1.0.0.gem
Fetching tzinfo-2.0.4.gem
Fetching crass-1.0.6.gem
Fetching zeitwerk-2.5.3.gem
Fetching activesupport-7.0.1.gem
Fetching nokogiri-1.13.0-x86_64-darwin.gem
Fetching loofah-2.13.0.gem
Fetching rails-dom-testing-2.0
.... and lot's of things
Installing ri documentation for actionmailbox-7.0.1
Parsing documentation for websocket-extensions-0.1.5
Installing ri documentation for websocket-extensions-0.1.5
Parsing documentation for websocket-driver-0.7.5
Installing ri documentation for websocket-driver-0.7.5
Parsing documentation for nio4r-2.5.8
Installing ri documentation for nio4r-2.5.8
Parsing documentation for actioncable-7.0.1
Installing ri documentation for actioncable-7.0.1
Parsing documentation for rails-7.0.1
Installing ri documentation for rails-7.0.1
Done installing documentation for zeitwerk, thor, method_source, tzinfo, activesupport, nokogiri, crass, loofah, rails-html-sanitizer, rails-dom-testing, rack, rack-test, erubi, builder, actionview, actionpack, railties, mini_mime, marcel, activemodel, activerecord, globalid, activejob, activestorage, actiontext, mail, actionmailer, actionmailbox, websocket-extensions, websocket-driver, nio4r, actioncable, rails after 37 seconds
33 gems installed
Don’t bother much about them, let’s check if Rails works. First check the rails version by typing rails -v
in terminal. I got this output
$ rails -v
Rails 7.0.1
So I have got a Rails version of 7 installed on my system.
For that let’s create a dummy app. Type rails new checking_rails
in your terminal:
$ rails new checking_rails
create
create README.md
create Rakefile
create .ruby-version
create config.ru
create .gitignore
create .gitattributes
create Gemfile
run git init from "."
create vendor/javascript
create vendor/javascript/.keep
Ensure JavaScript files are in the Sprocket manifest
append app/assets/config/manifest.js
Configure importmap paths in config/importmap.rb
create config/importmap.rb
Copying binstub
create bin/importmap
rails turbo:install stimulus:install
Import Turbo
append app/javascript/application.js
Pin Turbo
append config/importmap.rb
Run turbo:install:redis to switch on Redis and use it in development for turbo streams
Create controllers directory
create app/javascript/controllers
create app/javascript/controllers/index.js
create app/javascript/controllers/application.js
create app/javascript/controllers/hello_controller.js
Import Stimulus controllers
append app/javascript/application.js
Pin Stimulus
append config/importmap.rb
Once again it will throw a lot of stuff, don’t bother about it. When its over you would see a folder named checking_rails
, cd
into it and type rails server
or rails s
.
$ cd checking_rails
$ rails s
Once done you would see some output like this
$ rails s
=> Booting Puma
=> Rails 7.0.1 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 5.5.2 (ruby 3.1.0-p0) ("Zawgyi")
* Min threads: 5
* Max threads: 5
* Environment: development
* PID: 10515
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
If you read it, you might have noticed that Rails is running and is listening in port 3000. Open up your browser and type https://localhost:3000 in browser, press enter and you should get something like this:
If you see your terminal you will see something like this one:
$ rails s
=> Booting Puma
=> Rails 7.0.1 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 5.5.2 (ruby 3.1.0-p0) ("Zawgyi")
* Min threads: 5
* Max threads: 5
* Environment: development
* PID: 10515
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop
Started GET "/" for 127.0.0.1 at 2022-01-08 10:50:41 +0530
(2.4ms) SELECT sqlite_version(*)
Processing by Rails::WelcomeController#index as HTML
Rendering /Users/mindaslab/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.1/lib/rails/templates/rails/welcome/index.html.erb
Rendered /Users/mindaslab/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.1/lib/rails/templates/rails/welcome/index.html.erb (Duration: 2.0ms | Allocations: 882)
Completed 200 OK in 17ms (Views: 7.0ms | ActiveRecord: 0.0ms | Allocations: 7970)
Notice these logs in the terminal:
Started GET "/" for 127.0.0.1 at 2022-01-08 10:50:41 +0530
(2.4ms) SELECT sqlite_version(*)
Processing by Rails::WelcomeController#index as HTML
Rendering /Users/mindaslab/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.1/lib/rails/templates/rails/welcome/index.html.erb
Rendered /Users/mindaslab/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.1/lib/rails/templates/rails/welcome/index.html.erb (Duration: 2.0ms | Allocations: 882)
Completed 200 OK in 17ms (Views: 7.0ms | ActiveRecord: 0.0ms | Allocations: 7970)
It tells that you have visited the home page:
Started GET "/" for 127.0.0.1 at 2022-01-08 10:50:41 +0530
It gives a hint that Rails use sqlite DB https://sqlite.org/index.html out of the box:
(2.4ms) SELECT sqlite_version(*)
And finally it says that your request has been completed:
Completed 200 OK in 17ms (Views: 7.0ms | ActiveRecord: 0.0ms | Allocations: 7970)
It also says it took 17ms to complete this request. If other things are not understandable, never bother, you will get it.
To terminate rails press ctrl+c
in your keyboard and it will end. If all went well, you have successfully installed Rails and verified it. During exit you might get a message as shown:
^C- Gracefully stopping, waiting for requests to finish === puma shutdown: 2022-01-08 10:54:57 +0530 === - Goodbye! Exiting
Which says Rails has exited well.
Your Rails Development Environment
Hello Rails
In this section let’s relax and build our first Rails app, let’s name it hello_rails
, let’s first start by creating a new Rails app in our terminal.
Creating a new Rails app
step_0
$ rails new hello_rails
When you execute the above command, you will see a lot of output generated as shown below, never mind them.
create
create README.md
create Rakefile
create .ruby-version
create config.ru
create .gitignore
create .gitattributes
create Gemfile
run git init from "."
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /Users/mindaslab/code/rails_7/hello_rails/.git/
create app
create app/assets/config/manifest.js
create app/assets/stylesheets/application.css
create app/channels/application_cable/channel.rb
create app/channels/application_cable/connection.rb
create app/controllers/application_controller.rb
create app/helpers/application_helper.rb
create app/jobs/application_job.rb
create app/mailers/application_mailer.rb
create app/models/application_record.rb
create app/views/layouts/application.html.erb
....
create config/importmap.rb
Copying binstub
create bin/importmap
rails turbo:install stimulus:install
Import Turbo
append app/javascript/application.js
Pin Turbo
append config/importmap.rb
Run turbo:install:redis to switch on Redis and use it in development for turbo streams
Create controllers directory
create app/javascript/controllers
create app/javascript/controllers/index.js
create app/javascript/controllers/application.js
create app/javascript/controllers/hello_controller.js
Import Stimulus controllers
append app/javascript/application.js
Pin Stimulus
append config/importmap.rb
Once that’s done, cd
into hello_rails
you can run rails s
or rails server
in the terminal and open https://localhost:3000 in terminal and you will get the Rails first screen as shown below.
Press Ctrl+C
to exit Rails in terminal.
Static pages
Let’s create something called static pages, that is these are web pages who’s content does not change with time. for that type this in the terminal.
$ rails g controller welcome hello wish
You should be getting an output like the one shown below.
create app/controllers/welcome_controller.rb
route get 'welcome/hello'
get 'welcome/wish'
invoke erb
create app/views/welcome
create app/views/welcome/hello.html.erb
create app/views/welcome/wish.html.erb
invoke test_unit
create test/controllers/welcome_controller_test.rb
invoke helper
create app/helpers/welcome_helper.rb
invoke test_unit
Now start the rails server by punching rails s
in terminal, and visit http://localhost:3000/welcome/hello and you will be getting a screen like this one.
When you visit the url http://localhost:3000/welcome/wish, you will be getting a display as shown below in the browser.
What happened?
To an external observer this might look magical, it looks as though some request has been sent to the Rails (red box shown below), and a response had been got, but how does that happen?
So, if you see in routes.rb, you will see a code like this:
Rails.application.routes.draw do
get 'welcome/hello'
get 'welcome/wish'
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
# root "articles#index"
end
So when you hit this url http://localhost:3000/welcome/hello, notice that welcome/hello
in the url, and it’s been defined in routes.rb
, this tells rails to accept this route.
If you can split this route, you would get 'welcome`, a /
and hello
, now take a look at welcome_controller.rb
class WelcomeController < ApplicationController
def hello
end
def wish
end
end
The WelcomeController
is a Ruby class that inherits from ApplicationController
. ApplicationController
does lot of stuff that is beyond the scope of this book, so let’s for get about it. But in your url, you did have hello
in it. If you see the code in above welcome_controller.rb, you have a method called hello
: which is defined as follows:
def hello
end
So one could infer get 'welcome/hello'
allows a URL like http://localhost:3000/welcome/hello to be received by Rails. The welcome
in URL gets mapped to WelcomeController
which resides in a file app/controllers/welcome_controller.rb
, and hello
in the URL get’s mapped function WelcomeController#hello
.
Now checkout the file hello.html.erb
, you can see its in app/views/welcome/hello.html.erb
an it reads as follows
<h1>Welcome#hello</h1>
<p>Find me in app/views/welcome/hello.html.erb</p>
It’s this content that get’s displayed when you type http://localhost:3000/welcome/hello in the browser.
So this is what happens, first your request hits the route, the route sees if the URL cold be allowed in, then it routes to the right controller and action as shown below.
The the URL contains welcome/hello
, by convention Rails knows that there should be a controller named WelcomeController
should be defined in a file in app/controllers/welcome_controller.rb
and that file must have an action WelcomeController#hello
. By convention Rails knows that view for the file should be present in app/views/hello.html.erb
, so the controller pulls the view of the action and renders it out as response and you see a display like this
in your browser.
Changing views, linking pages
step_2
Now let’s change our view files and link then so that we have some form of navigation. Open app app/views/welcome/hello.html.erb
, and change it as shown:
<h1>
Hello from Rails!
</h1>
<p>
Hello and welcome to Rails.
</p>
<p>
<%= link_to "Wish Me", {action: :wish} %>
</p>
Notice the <%= link_to "Wish Me", {action: :wish} %>
, the file name is hello.html.erb
, here the .html
says it will be rendered as HTML, but the .erb
means Embedded Ruby. So we can put a valid Ruby between <%=
and %>
, and it will be embedded in the web page.
We put the following thing link_to "Wish Me", {action: :wish}
in it, this is nothing but link_to method that’s defined in the rails gem, you can get its documentation here https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to.
The first argument we pass to link to the text that must appear in the web page here its "Wish Me"
, the second argument should be the URL, so here we tell it to navigate to action wish by passing this hash {action: :wish}
, we embed the code in HTML using this ERB syntax: <%= link_to "Wish Me", {action: :wish} %>. This generates a web page as shown:
Similarly in app/views/welcome/wish.html.erb
, let’s put the following content into it:
<h1>
Have a nice day!
</h1>
<p>
<%= link_to "Go Back", {action: :hello} %>
</p>
Here <%= link_to "Go Back", {action: :hello} %>
generates a hyperlink with text Go Bak, and it will be linked to action hello.
Fire up your rails server in terminal by typing rails s
, when you hit the URL http://localhost:3000/welcome/hello, you will see a page as shown:
When you click Wish Me, you will be taken to a page that displays the content in wish me as shown below:
You could click Go Back to go to your hello page once again.
Dynamic pages
step_3
In the last section we have seen how to add static pages to Rails applications. Static pages are web pages that do not change with time, but what if we want to show pages who content is dynamic? We will see that here.
To do that open routes.rb and add this get 'welcome/time'
as shown below:
Rails.application.routes.draw do
get 'welcome/hello'
get 'welcome/wish'
get 'welcome/time'
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
# root "articles#index"
end
We tell Rails to respond to another route which is http://localhost:3000/welcome/time, when user hits that URL from his browser we will show him tthe time.
Now let’s add an action called time in WelcomeController
as shown.
class WelcomeController < ApplicationController
def hello
end
def wish
end
def time
end
end
Once added app/controllers/welcome_controller.rb
should look as shown above.
Now create a file called app/views/welcome/time.html.erb
as shown below
<h1>
Time
</h1>
<p>
The time now is <%= Time.now %>
</p>
Note these lines:
<p>
The time now is <%= Time.now %>
</p>
In the above piece of code note <%= Time.now %>
, we are getting an instance of Time
using Time.now
and embedding into the web page by placing it between <%=
and %>
.
Now visit http://localhost:3000/welcome/time, you should be getting output similar to the image shown below:
Refresh the page, the time should have changed. We created a dynamic page using Rails.
Moving code to action
step_4
It’s okay to have some code in view, but views should be more of pure views as much as possible, it’s better to move any code in view to corresponding action in the controller. So delete <%= Time.now %>
in app/views/welcome/time.html.erb
and replace it with <%= @time %>
<h1>
Time
</h1>
<p>
The time now is <%= @time %>
</p>
As you see @time
is an instance variable, and where do we define it? We define it in action time
in WelcomeController
as shown below:
class WelcomeController < ApplicationController
def hello
end
def wish
end
def time
@time = Time.now
end
end
Once done, refresh the page, the functionality would be the same.
But do remember that you have made the code bit better.
A common navigation
step_5
When you visit http://localhost:3000/welcome/home, you get a link to navigate to wish page and when you visit wish page, you get a link to go back to home. Now we have added a page to show time too, we have increased complexity of our app. It would be great if we have a common navigation in all pages where we can jump to any other page.
So in app/views/welcome/
, create a file called _nav.html.erb
, and fill it with content as shown below:
<ul>
<li>
<%= link_to "Hello Rails!", {action: :hello} %>
</li>
<li>
<%= link_to "Wish Me", {action: :wish} %>
</li>
<li>
<%= link_to "Time", {action: :time} %>
</li>
</ul>
So in the code above we have put three link_to
which point to all three actions. The file has an underscore at the beginning to denote that it’s a partial. That is this not a a full view code, but it’s a piece code that can be reused in other places.
Now let’s embed this _nav.html.erb
in hello.html.erb
as shown:
<h1>
Hello from Rails!
</h1>
<p>
Hello and welcome to Rails.
</p>
<p>
<%= render 'nav' %>
</p>
Notice the <%= render 'nav' %>
which looks for _nav.html.erb
in app/views/welcome/
and embeds its content between the <p>
and </p>
tags.
Similarly let’s embed _nav.html.erb
in time.html.erb
<h1>
Time
</h1>
<p>
The time now is <%= @time %>
</p>
<p>
<%= render 'nav' %>
</p>
and in wish.html.erb
as shown:
<h1>
Have a nice day!
</h1>
<p>
<%= render 'nav' %>
</p>
Now when you visit http://localhost:3000/welcome/hello, you will see a screen with navigation links as shown:
These links appear in http://localhost:3000/welcome/wish
and in http://localhost:3000/welcome/time as shown:
Happy hoppin pages!
Changing default landing page
step_6
When you type https://localhost:3000 in your browser, you get default Rails 7 page as shown:
Won’t it be great if it directly routs to welcome/hello
when we type https://localhost:3000
in browser?
To do that add root "welcome#hello"
in routes.rb as shown below:
Rails.application.routes.draw do
get 'welcome/hello'
get 'welcome/wish'
get 'welcome/time'
root "welcome#hello"
end
Now type https://localhost:3000 or refresh the browser and you will get hello page displayed as shown: