A Rails Blog In VS Code-Devise

How To Create A Blog in VS Code — Part V — RailsSeries#Episode 07

J3
Jungletronics
24 min readJul 15, 2023

--

Let’s Use Devise.

In this post:

You will:

Learn how to use the Devise;

Devise come pre-built with
password field
that is already encrypted.

You won't even be able to see them,
which is good for your user
because it means
you can't form their password
and email combinations but also
means you don't have to create
all the encryption yourself.

It also may confirm
user registrations through emails,
if you set it up, which is a pretty
simple setup, you'll see...

You can recover accounts.

You can do all the basic stuff that
you'd expect with a user registration
system account in another app.

That just comes out of the
box 🕋️ here, with Devise,
with just a little bit of setup.

Welcome!
Fig. 0: This post is a continuation of this one; This is a working code: 👉️rails_blog_v5

Let’s Get Started!
Note: If you get stuck, please see my repo.

0#step — Download the last post here and prepare your vscode environment.

Let’s open a new branch: git checkout -b add_devise

1#step — GoTo Gemfile and set Devise:

gem "devise"

2#step — Run bundle:

bundle install
output:

Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies…

Fetching orm_adapter 0.5.0

Fetching bcrypt 3.1.19

Fetching warden 1.2.9

Fetching responders 3.1.0
Using stimulus-rails 1.2.1
Installing orm_adapter 0.5.0
Installing warden 1.2.9
Installing bcrypt 3.1.19 with native extensions
Installing responders 3.1.0
Fetching devise 4.9.2
Installing devise 4.9.2
Bundle complete! 17 Gemfile dependencies, 78 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
Post-install message from devise:
[DEVISE] Please review the [changelog] and [upgrade guide] for more info on Hotwire / Turbo integration.
[changelog] https://github.com/heartcombo/devise/blob/main/CHANGELOG.md
[upgrade guide] https://github.com/heartcombo/devise/wiki/How-To:-Upgrade-to-Devise-4.9.0-%5BHotwire-Turbo-integration%5D

3#step —Run:

rails g devise:install

The code rails g devise:install is a Rails command used to generate the necessary files and configuration for the Devise gem in a Rails 7 application.

Devise is a popular authentication solution for Rails applications, providing a set of pre-built controllers, views, and models to handle user registration, authentication, and session management. It simplifies the process of implementing user authentication features in a Rails application.

Running rails g devise:install performs the following tasks:

  1. It generates an initializer file (config/initializers/devise.rb) that contains configuration options for Devise. You can modify this file to customize the behavior of Devise in your application.
  2. It creates a migration file to add the necessary columns to the database table used for storing user information. This migration file is placed in the db/migrate directory and will be used to create the required tables when you run rails db:migrate.
  3. It inserts the necessary routes for Devise in the config/routes.rb file. These routes provide endpoints for user authentication, registration, password management, and more.

After running rails g devise:install, you may need to run additional commands to generate other Devise-related components, such as the user model and views for authentication forms. These can be generated using commands like rails g devise User or rails g devise:views or rails g devise:controllers users. Keep reading, please…

Note: It’s always recommended to refer to the official documentation or release notes for the most up-to-date information.

rails g devise:install

output:

create config/initializers/devise.rb
create config/locales/devise.en.yml
===============================================================================

Depending on your application's configuration some manual setup may be required:

1. Ensure you have defined default url options in your environments files. Here
is an example of default_url_options appropriate for a development environment
in config/environments/development.rb:

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

In production, :host should be set to the actual host of your application.

* Required for all applications. *

2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:

root to: "home#index"

* Not required for API-only Applications *

3. Ensure you have flash messages in app/views/layouts/application.html.erb.
For example:

<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>

* Not required for API-only Applications *

4. You can copy Devise views (for customization) to your app by running:

rails g devise:views

* Not required *

===============================================================================

4#step — Run:

rails g devise User

When you run rails g devise User, it performs the following tasks:

  1. It generates a model file for the User model (app/models/user.rb). This file will include the necessary code to integrate with Devise and handle user authentication-related functionality.
  2. It creates a migration file to add additional columns to the users table in the database. These columns are required by Devise for storing user information such as encrypted passwords, timestamps, and other authentication-related data. The migration file is placed in the db/migrate directory and can be executed using rails db:migrate to apply the database changes.
  3. It generates a locale file (config/locales/devise.en.yml) that contains translations for Devise error messages and other text displayed by Devise.
  4. It creates a views directory for the User model (app/views/devise/users) containing a set of view templates for user authentication-related views such as sign-up, sign-in, password reset, and more. These views can be customized to match the look and feel of your application.

In addition to generating the User model and associated files, the rails g devise User command will also update the config/routes.rb file to include the necessary routes for user authentication, registration, and session management.

It’s worth noting that User is just an example model name. You can replace User with the name of your own model if you want to use a different name for your user model, such as Admin or Customer.

rails g devise User

output:

invoke active_record
create db/migrate/20230714162304_devise_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
insert app/models/user.rb
route devise_for :users

Before running the migration, you can see this file:/db/migrate/20230714162304_devise_create_users.rb. We customize it in this post about email.

But for now, just migrate…

5#step — run:

rails db:migrate
output: 

== 20230714162304 DeviseCreateUsers: migrating ================================
-- create_table(:users)
-> 0.0013s
-- add_index(:users, :email, {:unique=>true})
-> 0.0007s
-- add_index(:users, :reset_password_token, {:unique=>true})
-> 0.0005s
== 20230714162304 DeviseCreateUsers: migrated (0.0026s) =======================
6

To generate the necessary files to apply the database changes required by the Devise User model.

It creates reset_password_token, which is unique. So what does it mean? It means if you have to recover the email you send to the applicant a hash to recover their account; it will find the user based on the reset password token. It is unique because it needs to only apply to that user of course.

Inform yourself about GDPR. Non-compliance with the GDPR can result in significant fines.

GDPR stands for General Data Protection Regulation. It is a comprehensive data protection and privacy law introduced by the European Union (EU) and came into effect on May 25, 2018. The GDPR was designed to provide individuals with greater control over their personal data and to harmonize data protection regulations across the EU member states.

In Brazil we have LGPDLei Geral de Proteção de Dados Pessoais (LGPD), Lei n° 13.709/2018.

6#step — Create a partial file to flash message decently at:

app/views/layouts/_messages.html.erb

<% if notice %>
<div class="alert alert-success" >
<button type="button" class="btn-close float-end" data-bs-dismiss="alert" aria-label="Close"></button>
<%# <button type="button" class="close" data-dismiss="alert" aria-label="Close"> %>
<span aria-hidden="true">&times;</span>
</button>
<%= notice %>
</div>
<% end %>
<% if alert %>
<div class="alert alert-danger">
<button type="button" class="btn-close float-end" data-bs-dismiss="alert" aria-label="Close"></button>
<%# <button type="button" class="close" data-dismiss="alert" aria-label="Close"> %>
<span aria-hidden="true">&times;</span>
</button>
<%= alert %>
</div>
<% end %>

This will add a flash message to your rails page. It is dismissible & colorized. when you click on the X, it will close the message. Error is shown in red, regular action, in green. Just neat!

To take effect, please execute Step #7 below.

7#step — GoTo and inside <body> type:

rails-blog-demo/app/views/layouts/application.html.erb

...
<header>
<%= render 'layouts/navbar' %>
<%= render 'layouts/messages'%>
</header>
<main>
<div class="container">
<%= yield %>
</div>
</main>
...

To streamline and prevent redundancy, you may remove the following line from both the show.html.erb and index.html.erb pages from app/views/posts/ and app/views/users/ directories:

<p style="color: green"><%= notice %></p>

This will help maintain consistency and improve the clarity of your code

8#step —Extract the code block from the last <li> to </li> within the partial file and replace it with <%= render 'user/session_manager' %>. This will deal with session management.

rails-blog-demo/app/views/layouts/_navbar.html.erb

...

<ul class="navbar-nav">
<%= render 'user/session_manager' %>
</<ul>

...

Check out the finished design of our navbar!

<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="/home">Rails Blog</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<%# <a class="nav-link active" aria-current="page" href="#">Home</a> %>
<%= link_to "Home", root_path, class: 'nav-link' %>
</li>
<li class="nav-item">
<%= link_to "Blog", posts_path, class: 'nav-link' %>
</li>
<li class="nav-item">
<%= link_to "About", about_path, class: 'nav-link' %>
</li>
</ul>
<ul class="navbar-nav">
<%= render 'user/session_manager' %>
</ul>
</div>
</div>
</nav>

We will substitute the dropdown text with User Functionality in the extracted code. This will serve as a placeholder until step #29 when we will address sessions.

Create a folder at app/views/user.

9#step —Create a session management file within the new app/views/user directory and Paste the content previously extracted to:

app/views/user/_session_manager.html.erb:

<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
User Functionality
</a>
<ul class="dropdown-menu dropdown-menu-lg-end" aria-labelledby="navbarDropdown">
<li><%= link_to "New Post", new_post_path , class: "dropdown-item" %></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><%= link_to "Edit Account", edit_user_registration_path, class:"dropdown-item" %></li>
<li><hr class="dropdown-divider"></li>
<li><%= button_to "Sign out", destroy_user_session_path, method: :delete, class:"dropdown-item" %></li>
</ul>
</li>

Note: Before navigating to app/views/user and placing this partial inside, ensure you create the necessary folder and file. Moving forward, let’s proceed to manage the session; this is where we’ll handle individual sessions, which is why we set the directory user in singular form.

Our blog’s navbar, particularly positioned at the end, directs users to the registration & authentication pages, and sessions & posts management actions. It provides easy access to different pages quickly.

This is the actual navbar look and feel…
Now, let’s distinguish between the two statuses: one when the user is logged in, and the other when the user is not logged in... Keep reading!

10#step — Create a structure like this inside this partial:

app/views/user/_session_manager.html.erb:

<% if current_user %>
[IF USER IS LOGGED IN]
<% else %>
[IF USER IS NOT LOGGED IN]
<% end %>
<% if current_user %>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
User Functionality Goes here!
</a>
<ul class="dropdown-menu dropdown-menu-lg-end" aria-labelledby="navbarDropdown">
<li><%= link_to "New Post", new_post_path , class: "dropdown-item" %></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><%= link_to "Edit Account", edit_user_registration_path, class:"dropdown-item" %></li>
<li><hr class="dropdown-divider"></li>
<li><%= button_to "Sign out", destroy_user_session_path, method: :delete, class:"dropdown-item" %></li>
</ul>
</li>
<% else %>
<li class="nav-item">
<%= link_to "Sign up", new_user_registration_path, class: 'nav-link' %>
</li>
<li class="nav-item">
<%= link_to "Login", new_user_session_path, class: 'nav-link' %>
</li>
<% end %>

When you enter rails routes | grep users into the Terminal, concerning this post, you’ll encounter the following table:

Warning: if you destroy registration (instead of destroying a session) you destroy the account entirely (new_user_registration_path); So take care!

If you destroy sessions, the user’s session will be terminated, resulting in the user being logged out (redirected to new_user_session_path). Ensure a secure logout process with this approach!

11#step — Let’s make the sign_out (logout)button inside dropdown menu, right after the dropdown divider:

rails-blog-demo/app/views/user/_session_manager.html.erb

<li><%= button_to "Sign out", destroy_user_session_path, method: :delete, class:"dropdown-item" %></li>
Fig. 2: Now we have a functioning sign-out link, as well as New Posts from before...
Fig. 3: …In the navbar Sign up and Login links will appear if the user is not logged in. Cool!

12#step — Could you please confirm that the new post link is functioning correctly? So far, so good!

But there is a problem here: there’s nothing to stop us from going to this link /post/new from anywhere;

Try it by typing CTRL + SHIFT + N and opening an incognito window. Then, paste http://127.0.0.1:3000/posts/new into the address bar, and you will see the form. No users are logged in!

It is better to control access to your system through user signing and authentication.

How can we accomplish this? inside posts_controller.rb file.

rails-blog-demo/app/controllers/posts_controller.rb

class PostsController < ApplicationController
...
before_action :authenticate_user!, except: %i[show index]
....

In Rails 7, the code snippet before_action :authenticate_user!, except: %i[show index] is used to define a before_action filter in a controller. This filter ensures that the authenticate_user! method is called before executing any actions in the controller, except for the show and index actions.

The before_action method is a common feature in Rails that allows you to specify a method or a block of code that should be executed before certain actions in a controller. In this case, authenticate_user! is a common method used in authentication systems to ensure that a user is logged in before accessing certain actions or pages.

By specifying except: %i[show index], you are instructing Rails to skip the authenticate_user! method for the show and index actions. This means that these actions can be accessed without requiring authentication, while other actions in the controller will still enforce the authentication requirement.

This can be useful in cases where you have certain public-facing pages or actions that don’t require user authentication, such as a blog’s index page or a public show page, while still enforcing authentication for other actions that deal with sensitive or protected data.

Fig. 4: Now it takes us to the SIGN IN page. Cool!

13#step — Now let’s associate user with the posts, on Terminal type:

rails g migration add_user_to_posts user:belongs_to

In Rails 7, the command rails g migration add_user_to_posts user:belongs_to is used to generate a new migration file that adds a user_id column to the posts table, establishing a "belongs_to" association between the Post model and the User model.

14#step — Now association: ORM; GoTo:

rails-blog-demo/app/models/post.rb

class Post < ApplicationRecord
validates :title, presence: true, length: { maximum: 5, maximum: 50 }
validates :body, presence: true, length: { minimum: 10, maximum: 1000 }
belongs_to :user
end

15#step — And GoTo:

rails-blog-demo/app/models/user.rb

class User < ApplicationRecord
has_many :posts
...
end
Fig. 5: ORM Association graphically explained: Just an amazingly simple graph explanation! made with: https://excalidraw.com/ 😍️ Object Relational Mapping: commonly referred to by its abbreviation ORM, is a technique that connects the rich objects of an application to tables in a relational database management system. Everything you did above is illustrated here. Pretty neat!👌️!

16#step — GoTo Rails Console and destroy all the post to avoid this error 👇️ before running migration:

SQLite3::ConstraintException: NOT NULL constraint failed: posts.user_id

rails c
Post.destroy_all
exit

17#step — Now run migrate:

rails db:migrate

18#step — GoTo seeds.rb and refactor it (now each post must have user id):

rails-blog-demo/db/seeds.rb

User.create(email: 'example@example.com', password: 'password', password_confirmation: 'password')

10.times do |i|
Post.create(title: "Title #{i}", body: "Body #{i} words goes here idk...", user_id: User.first.id)
end

19#step — Re-populate the table by running seed:

rails db:seed

20 #step — To Identify the author’s post, GoTo and type <h4>:

rails-blog-demo/app/views/posts/_post.html.erb

<div id="<%= dom_id post %>">
<h2><%= post.title %></h2>
<h4>Posted by <% post.user.email %></h4>
<h6><%= pluralize(post.views, "view")%></h6>
<div>
<%= post.body %>
</div>
</div>

21#step — We just have a column email. Let’s add a name to our User database. GoTo Terminal type:

rails g migration add_name_to_user name:string
rails db:migrate

In Rails 7, the command rails g migration add_name_to_user name:string is used to generate a new migration file that adds a name column to the users table.

This migration is typically used when you want to add a new attribute called name to the User model, allowing users to have a name associated with their account. Now:

rails db:migrate

By running this migration (rails db:migrate), the name column will be added to the users table in the database, with the data type of string. This means that each user record will have a corresponding name field, where you can store the user's name as a string value.

After the migration is executed, you can access the name attribute on the User model just like any other attribute. For example, if you have an user object, you can retrieve the name by calling user.name.

This migration is useful when you want to extend the default attributes of the User model in your application to include additional information like the user's name.

22#step — GoTo set edit link:

rails-blog-demo/app/views/user/_session_manager.html.erb

<li><%= link_to "Edit Account", edit_user_registration_path, class:"dropdown-item" %></li>
Fig. 6: Now we have an Edit account link in the dropdown menu. 😘️
Fig. 7: To see all the routes available on Terminal run rails s and point your browser to http://127.0.0.1:3000/rails/routes/info or on Console type rails routes --expanded ❤️‍🩹️
Fig. 8: More here…
Fig. 9: and more…

23#step — Now Devise views, Run:

rails g devise:views  
output: 

invoke Devise::Generators::SharedViewsGenerator
create app/views/devise/shared
create app/views/devise/shared/_error_messages.html.erb
create app/views/devise/shared/_links.html.erb
invoke form_for
create app/views/devise/confirmations
create app/views/devise/confirmations/new.html.erb
create app/views/devise/passwords
create app/views/devise/passwords/edit.html.erb
create app/views/devise/passwords/new.html.erb
create app/views/devise/registrations
create app/views/devise/registrations/edit.html.erb
create app/views/devise/registrations/new.html.erb
create app/views/devise/sessions
create app/views/devise/sessions/new.html.erb
create app/views/devise/unlocks
create app/views/devise/unlocks/new.html.erb
invoke erb
create app/views/devise/mailer
create app/views/devise/mailer/confirmation_instructions.html.erb
create app/views/devise/mailer/email_changed.html.erb
create app/views/devise/mailer/password_change.html.erb
create app/views/devise/mailer/reset_password_instructions.html.erb
create app/views/devise/mailer/unlock_instructions.html.erb

In Rails 7, the command rails g devise:views is used to generate the views associated with the Devise gem.

When you run rails g devise:views, it generates a set of view templates that can be customized to fit the design and functionality of your application. These views are stored in the app/views/devise directory.

The generated views include files such as registrations/new.html.erb (user registration form), sessions/new.html.erb (user login form), passwords/new.html.erb (password reset form), and others.

By running this command, you don’t need to create these views from scratch. Instead, Devise generates them for you, allowing you to quickly set up user authentication and customize the views as needed.

Once the views are generated, you can modify them to match your application’s styling, add additional fields, or customize the behavior according to your requirements. These views work in conjunction with the Devise controllers and models to provide the necessary authentication functionality in your Rails application (Devise is used for Registrations, Authentications, and Session Management — RASM).

24#step — Now Devise Controllers, Run:

rails g devise:controllers users
output:

create app/controllers/users/confirmations_controller.rb
create app/controllers/users/passwords_controller.rb
create app/controllers/users/registrations_controller.rb
create app/controllers/users/sessions_controller.rb
create app/controllers/users/unlocks_controller.rb
create app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================

Some setup you must do manually if you haven't yet:

Ensure you have overridden routes for generated controllers in your routes.rb.
For example:

Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions'
}
end

===============================================================================

By running rails g devise:controllers users, you generate custom controller files specifically for the users resource, which represents the user model in your application. These controller files will be placed in the app/controllers/users directory.

The generated controller files include:

  • confirmations_controller.rb: Handles account confirmation-related actions.
  • passwords_controller.rb: Handles password reset-related actions.
  • registrations_controller.rb: Handles user registration-related actions.
  • sessions_controller.rb: Handles user login and logout-related actions.
  • unlocks_controller.rb: Handles account unlocking-related actions.

But the two we want to take a look at are going to be registrations and session controllers.

These generated controller files allow you to override the default behavior of Devise controllers by adding or modifying the actions and their corresponding logic. This customization can include adding additional functionality, applying custom validation, or integrating with other parts of your application.

For example, you might want to add extra steps during the user registration process, implement additional authentication methods, or customize the behavior of password reset flows. By generating the custom controllers, you have a starting point to modify and extend the authentication behavior specifically for the users resource in your Rails application.

After running this command, you can modify the generated controller files according to your specific requirements and customize the authentication behavior for the users resource in your Rails application.

25#step — GoTo and create a name field just below email:

rails-blog-demo/app/views/devise/registrations/edit.html.erb

<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
Fig. 10: This is one of the devise’s default views which allows you to edit your user account information; you can cancel your account if you want to; you can change your email or change your password and then you’ll need to type your current password to update. Automagically! Just Amazing! 👌️

26#step — Upon creating a new post, let’s promptly save the information of the user who authored the post.

GoTo, and below @post = Post.new(post_params), type:

rails-blog-demo/app/controllers/posts_controller.rb

  def create
...
@post.user = current_user
...

We can do that because our authenticate user ( see Step#12 ) is making sure that we can never come to the create action unless we’re signed in so that will set the user of the post for us, which is neat!

27#step — To get everything working, please GoTo:

rails-blog-demo/config/routes.rb

 devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'
}

This code snippet is configuring Devise to handle user authentication and registration routes for a User model while using custom controllers to control the behavior of certain actions during the authentication and registration processes. In this case:

  • sessions: 'users/sessions': This points to the custom controller for handling user sessions (sign-in and sign-out). The controller would be located in the app/controllers/users/sessions_controller.rb file.
  • registrations: 'users/registrations': This points to the custom controller for user registrations (sign-up). The controller would be located in the app/controllers/users/registrations_controller.rb file.

28#step — GoTo and uncomment these protected methods:

rails-blog-demo/app/controllers/users/registrations_controller.rb

...

class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]

...
# protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
end

# If you have extra params to permit, append them to the sanitizer.
def configure_account_update_params
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end
...

Please remember to replace :attribute with :name as this is how we whitelist inputs in Devise.

Here we want to be able to update the account and white list a new parameter (name) so uncomment these too:

configure_sign_up_params
configure_account_update_params


To call each one, uncomment each before_action.

This is typically used in combination with strong parameters to prevent mass assignment vulnerabilities when you whitelist a new parameter in the controller using the permit method within the params hash, such as params.require(:post).permit(:title, :content, :new_parameter). But here, in Devise, you use sanitizer method — devise_parameter_sanitizer.permit(:account_update, keys: [:name]).

29#step — Now to render in the navbar the current user dot name,
Substitute the text User Functionality Goes Here! with the name of the logged-in user., GoTo:

rails-blog-demo/app/views/user/_session_manager.html.erb

<%= current_user.name %>

30#step —Now create a text input field where users can enter a value for the name attribute below email, GoTo:

rails-blog-demo/app/views/devise/registrations/new.html.erb

<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>

31#step —Now functionality related to user profile, GoTo Terminal, type:

rails g controller users profile
output:

create app/controllers/users_controller.rb
route get 'users/profile'
invoke erb
create app/views/users
create app/views/users/profile.html.erb
invoke test_unit
create test/controllers/users_controller_test.rb
invoke helper
create app/helpers/users_helper.rb
invoke test_unit

The code rails g controller users profile in Rails 7 is a command used to generate a new controller named UsersController with an action named profile.

When you run this command, Rails generates several files for you:

  1. app/controllers/users_controller.rb: This file contains the UsersController class definition. It is where you can define the actions and logic for handling requests related to the users resource.
  2. app/views/users/profile.html.erb: This file is the view template for the profile action. It is an HTML.erb file where you can write the HTML and embedded Ruby code to define the content that will be displayed when the profile action is accessed.
  3. Other files such as test files and helper files may also be generated, depending on your Rails configuration.

The purpose of generating this controller and action is to provide a starting point for implementing functionality related to user profiles within your Rails application. The UsersController can include methods to handle user profile-related actions, such as displaying user information, allowing users to edit their profiles, or performing any other actions specific to user profiles.

You can customize the generated UsersController and profile.html.erb files to fit your application's requirements. You can add additional actions, define instance variables to pass data to the view, and modify the view template as needed to display the user profile information or perform other desired actions related to user profiles.

Note about the importance of profile pages:


Profile generally refers to a set of characteristics,
attributes, or information that describes an individual
or entity. In the context of software applications,
a “profile” often refers to a user’s personal or
professional information that they have provided or
that has been generated by their interactions within
the application. This information might include things
like personal details, preferences, settings,
activity history, or any other relevant data that helps
characterize or identify the user within the system.
Profiles are commonly used in social networking sites,
online forums, e-commerce platforms, and various other
types of applications to customize user experiences and
provide personalized content or services.


In Rails, a controller named users_profile typically
serves the purpose of managing actions related to user
profiles within an application. This controller would
handle requests and responses associated with viewing,
editing, updating, or deleting user profiles.
It helps to keep the code organized by separating
concerns related specifically to user profiles from
other parts of the application logic.

32#step — Add views count to the User table, GoTo Terminal, type:

rails g migration add_views_to_user views:integer
output:

invoke active_record
create db/migrate/20230714232351_add_views_to_user.rb

By running this command and then executing the migration (rails db:migrate), the views column will be added to the users table in the database. The data type of the views column is specified as integer, indicating that it will store numeric values.

33#step — To create the field, GoTo Terminal, type:

rails db:migrate
output: 

== 20230714232351 AddViewsToUser: migrating ===================================
-- add_column(:users, :views, :integer)
-> 0.0015s
== 20230714232351 AddViewsToUser: migrated (0.0016s) ==========================
Fig. 11. The DB final result.

34#step —Opps, let’s change the schema of the users table to set the default value, on terminal type:

rails g migration change_views_for_users
output:

invoke active_record
create db/migrate/20230714232857_change_views_for_users.rb

The code rails g migration change_views_for_users in Rails 7 is a command used to generate a new migration file for changing the schema of the users table, specifically modifying the views column.

The purpose of this migration file is to define the changes you want to make to the users table regarding the views column.

35#step — Now to add a default value, Navigate to db/migrate, select the latest migration file, and then enter:

class ChangeViewsForUsers < ActiveRecord::Migration[7.0]
def change
change_column :users, :views, :integer, default: 0
end
end

36#step — Run migration:

rails db:migrate

37#step — Now route configuration map, above to resources :posts, GoTo:

rails-blog-demo/config/routes.rb

get 'u/:id', to: 'users#profile', as: 'user'

This route configuration maps a GET request to the URL path 'u/:id' to the profile action of the UsersController, and it gives the route a named route helper of 'user'.

Here’s a breakdown of what each part of the code does:

  • get: This specifies that this route will respond to HTTP GET requests.
  • 'u/:id': This is the URL pattern that the route will match. It uses a parameterized segment :id to capture the user's ID as part of the URL path. For example, a request to /u/1 will match this route, with 1 being captured as the :id parameter.
  • to: 'users#profile': This indicates that the request should be routed to the profile action within the UsersController. It specifies the controller and action that will handle the request.
  • as: 'user': This assigns the route a named route helper, which allows you to generate URLs and paths for this route using the specified name. In this case, the route helper is named 'user', so you can use methods like user_path(id) or user_url(id) to generate the URL or path for a specific user's profile. The id argument should be replaced with the actual user ID.

Overall, this route configuration sets up a URL pattern that captures the user’s ID and maps it to the profile action in the UsersController. The named route helper 'user' makes it easier to generate URLs or paths for user profiles in your application.

38#step — Let’s implement the profile action functionality; GoTo:

rails-blog-demo/app/controllers/users_controller.rb and type:

class UsersController < ApplicationController
before_action :set_user
def profile
@user.update(views: @user.views + 1)
end

private

def set_user
@user = User.find(params[:id])
end
end

Here’s an explanation of what each part of the code does:

  • class UsersController < ApplicationController: This line declares the UsersController class, which is a subclass of ApplicationController. Controllers in Rails handle incoming requests and define actions to perform specific tasks.
  • before_action :set_user: This line specifies that the set_user method should be called as a before action before executing the profile action. It ensures that the @user instance variable is set and available for use in the profile action.
  • def profile: This defines the profile action within the UsersController. It is the action that will be executed when a request is made to the profile route for a specific user.
  • @user.update(views: @user.views + 1): In the profile action, this line updates the views attribute of the @user instance. It increments the value of views by 1 each time the profile action is called, essentially tracking the number of views for a user's profile.
  • private: This keyword specifies that the methods defined after it (set_user in this case) are private methods and cannot be accessed from outside the class. Private methods are typically used for internal implementation details.
  • def set_user: This is a private method that sets the @user instance variable by finding the user record based on the id parameter passed in the request. It uses User.find(params[:id]) to retrieve the user record from the database and assigns it to @user. The params[:id] represents the value of the id parameter in the request's URL.

Overall, this code sets up the UsersController with a profile action that increments the views attribute of the user each time the profile is accessed. It uses a before_action callback to ensure the @user instance variable is set before executing the profile action.

39#step — Let’s update all our users to have zero views; GoTo Rails Console by typing:

rails c
User.all.each do |user|
user.views = 0
user.save
end
output:

irb(main):005:1* User.all.each do |user|
irb(main):006:1* user.views = 0
irb(main):007:1* user.save
irb(main):008:0> end
User Load (0.1ms) SELECT "users".* FROM "users"
TRANSACTION (0.0ms) begin transaction
User Update (0.2ms) UPDATE "users" SET "updated_at" = ?, "views" = ? WHERE "users"."id" = ? [["updated_at", "2023-07-14 23:49:59.340777"], ["views", 0], ["id", 3]]
TRANSACTION (7.4ms) commit transaction
TRANSACTION (0.0ms) begin transaction
User Update (0.2ms) UPDATE "users" SET "updated_at" = ?, "views" = ? WHERE "users"."id" = ? [["updated_at", "2023-07-14 23:49:59.351222"], ["views", 0], ["id", 4]]
TRANSACTION (3.3ms) commit transaction
=>
[#<User views: 0, email: "giljr.2009@gmail.com", id: 3, created_at: "2023-07-14 21:26:23.681346000 +0000", updated_at: "2023-07-14 23:49:59.340777000 +0000", name: "gilberto">,
#<User views: 0, email: "test@test.com", id: 4, created_at: "2023-07-14 23:16:05.947085000 +0000", updated_at: "2023-07-14 23:49:59.351222000 +0000", name: "test">]
irb(main):009:0>
exit

This effectively resets the views count to 0 for all users in the system. Conversely, certain post view attributes might be invalid or null.

40#step — Let’s do a static text indicating the author of the post, GoTo:

rails-blog-demo/app/views/posts/_post.html.erb

<h4>Posted by <%= link_to post.user.name, user_path(post.user) %></h4>

Let’s break down what each part of the code does:

  • Posted by: This is a static text indicating the author of the post.
  • <%= link_to post.user.name, user_path(post.user) %>: This is an ERB code snippet that generates a link to the profile of the user who authored the post. It consists of two parts:
  • post.user.name: This accesses the name attribute of the user associated with the post. Assuming that the post object has an association with a User model, it retrieves the name of the user who created the post.
  • link_to: This is a helper method provided by Rails to generate HTML anchor tags. It creates a hyperlink to the specified URL.
  • user_path(post.user): This generates the URL path for the user's profile page, based on the user_path named route helper. It takes the post.user object (which represents the user who authored the post) as an argument and generates the appropriate URL.

Overall, this code generates an HTML heading (h4) that displays “Posted by” followed by a link to the profile of the user who authored the post. The user’s name is displayed as the link text, and clicking on it will direct the user to the profile page of the corresponding user.

41#step — The last modification, GoTo:

rails-blog-demo/app/controllers/posts_controller.rb and type:

  # GET /posts or /posts.json
def index
@posts = Post.all.order(created_at: :desc)
end

What does that do? well, if we now refresh the page we can see the most recent posts first!

That’s it:

Fig. 12: We strongly believe that including this blog in your online portfolio can raise your chances of getting your next gig.

42#step — Uploading to Heroku via GitHub merge request:


git status
git add -A
git commit -m ":lipstick: feat: Add Devise"
git push --set-upstream origin add_devise

Make this sequence.

Now GoTo Heroku and:

Fig. 13: Destroy Database
Fig. 14: Recreate DATABASE

git checkout master
git status
git fetch
git pull
git status

git push heroku master
heroku addons:destroy
heroku run rails db:migrate
heroku run rails db:migrate
heroku open
Fig. 15: On Heroku: https://j3-rails-blog-demo-5a0a55d44e12.herokuapp.com/posts

That’s All, Folks!

See you in the next episode: Post’s comments.👋️👋️👋️!

👉️ rails_blog_v5

For your convenience:

git checkout -b add_devise
bundle install
rails g devise:install
rails g devise User
rails db:migrate
rails s
rails g migration add_user_to_posts user:belongs_to
rails db:migrate
rails c
rails db:migrate
rails s
rails db:seed
rails s
rails c
rails s
rails g migration add_name_to_user name:string
rails db:migrate
rails s
rails g devise:views
rails s
rails g devise:controllers users
rails s
rails c
rails s
rails c
rails s
clear
rails g controller users profile
rails g migration add_views_to_user views:integer
rails db:migrate
rails g migration change_views_for_users
rails s
rails c
rails s
git status
git add -A
git commit -m ":lipstick: feat: Add Devise"
git push --set-upstream origin add_devise
git checkout master
git status
git fetch
git pull
git status
git push heroku master

heroku run rails db:migrate
heroku open

Credits & References

Based on: Deanins lessons:

Devise 4.8.1 + Rails 7.0.0 | Undefined method ‘user_url’ #5439

Related Posts:

00# Episode — RailsSeries — Installing Ruby on Rails Using ASDF — Why ASDF is Better Than RBENV for Rails Bootstrap App?

01# Episode — RailsSeries — How To Send Email In Rails 7? — User Registration and Onboarding.

02# Episode — RailsSeries — 14 Ruby Extensions 4 Vs Code — Based On This Deanin’s video.

03# Episode — RailsSeries — A Rails Blog In VS Code — Quick Start — How To Create A Blog in VS Code — Part I

04# Episode — RailsSeries — A Rails Blog In VS Code — Styling — How To Create A Blog in VS Code — Part II

05# Episode — RailsSeries — A Rails Blog In VS Code — Create Posts — How To Create A Blog in VS Code — Part III

06# Episode — RailsSeries — A Rails Blog In VS Code — Posts Tips&Tricks — How To Create A Blog in VS Code — Part IV

07# Episode — RailsSeries — A Rails Blog In VS Code — Devise — How To Create A Blog in VS Code — Part V (this one)

08# Episode — RailsSeries — A Rails Blog In VS Code — Add Comments to Post — How To Create A Blog in VS Code — Part VI

09# Episode — RailsSeries — Rails Blog In VS Code — Using Stimulus — How To Create A Blog in VS CodePart VII

10# Episode — RailsSeries — Rails Blog In VS Code — Noticed V1 — Notifications for your Ruby on Rails app — Part VIII

11# Episode — RailsSeries — Rails Blog In VS Code — Noticed V2 — Notifications for your Ruby on Rails app — Part IXFor v5 let’s Tag it all!

git tag -a rails_blog_v5 -m "Blog in Rails 7 - v1.0:  Go to  https://j3-rails-blog-demo-5a0a55d44e12.herokuapp.com/" -m "0- Add Devise to the Gemfile & Run bundle install;" -m "1- Generate the Devise configuration files;" -m "2- Generate a Devise model;" -m "3- Run the database migration;" -m "4- Customize the Devise views;" -m "5- Mount Devise routes;" -m "5- Restart your Rails server;" -m "5- Upload Rails 7 project to heroku." -m "Thank you for downloading this project 😘️👌️👋️😍️" 

git push origin rails_blog_v5

--

--

J3
Jungletronics

Hi, Guys o/ I am J3! I am just a hobby-dev, playing around with Python, Django, Ruby, Rails, Lego, Arduino, Raspy, PIC, AI… Welcome! Join us!