[Ruby] [Rails] Add Tags, which is a has_many relationship, to Devise’s User (addition of function to follow tags)

2 minute read

Introduction

By adding Tags which is a relationship of has_many to Devise User, we will create a function to follow tags like Qiita.

Environment

  • Language: Ruby 2.7.1
  • WEB framework: Ruby on Rails 5.2.4.3
  • Database: PostgreSQL 12.2
  • User authentication function: Devise 4.7.2

Overview

Devise does not have a username column by default. And there is lots of information on the net about how to add a username column. However, to create the ability to follow tags, we need to add Tags, which is a has_many relationship, and there isn’t much information on this. Therefore, I have summarized the method.

Code

You can download the Rails project here. https://github.com/GuiltyWorks/DeviseWithTags

bin/rails g migration add_name_to_users name:string bin/rails g model tag bin/rails g model user_tag_relation Create migration file to add name to User, Tag model and UserTagRelation model.

db/migrate/20200716151945_add_name_to_users.rb


class AddNameToUsers <ActiveRecord::Migration[5.2]
  def change
    add_column :users, :name, :string
  end
end

It’s not necessary, but we’ll add a username column because it’s all done.

db/migrate/20200716152422_create_tags.rb


class CreateTags <ActiveRecord::Migration[5.2]
  def change
    create_table :tags do |t|
      t.string :name, null: false, unique: true

      t.timestamps
    end
  end
end

Has a column for the name of the tag * name

  • do not allow null
  • Do not wear tag name

Create the tag table as above.

db/migrate/20200716152440_create_user_tag_relations.rb


class CreateUserTagRelations <ActiveRecord::Migration[5.2]
  def change
    create_table :user_tag_relations do |t|
      t.references :user, foreign_key: true
      t.references :tag, foreign_key: true

      t.timestamps
    end
  end
end

Create an intermediate table that associates users with tags.

app/models/user.rb


class User <ApplicationRecord
  # Include default devise modules.Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  validates :name, {presence: true}
  validates :email, {presence: true, uniqueness: true}

  has_many :user_tag_relations, dependent: :delete_all
  has_many :tags, through: :user_tag_relations
end

Describe has_many in the User model.

app/models/user_tag_relation.rb


class UserTagRelation <ApplicationRecord
  belongs_to :user
  belongs_to :tag
end

Describe belongs_to in the UserTagRelation model.

app/models/tag.rb


class Tag <ApplicationRecord
  validates :name, {presence: true, uniqueness: true}

  has_many :user_tag_relations, dependent: :delete_all
  has_many :users, through: :user_tag_relations
end

Describe has_many in the Tag model.

app/controllers/application_controller.rb


class ApplicationController <ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
    devise_parameter_sanitizer.permit(:sign_in, keys: [:name])
    devise_parameter_sanitizer.permit(:account_update, keys: [:name, tag_ids: []])
  end
end

Register name and tag_ids in Devise.

config/initializers/devise.rb


config.scoped_views = true

Set it to true instead of false to change the Devise view.

ERB:app/views/devise/registrations/new.html.erb


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

Allows you to set the user name on the new registration screen.

ERB:app/views/devise/registrations/edit.html.erb


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

<div class="field">
  <%= f.label :tag_ids, "Tags you want follow" %>
  <%= f.collection_check_boxes :tag_ids, Tag.all, :id, :name do |tag| %>
    <div class="form-check">
      <%= tag.label class: "form-check-label" do %>
        <%= tag.check_box class: "form-check-input" %>
        <%= tag.text %>
      <% end %>
    </div>
  <% end %>
</div>

Allows you to set the user name and tags to follow on the user settings screen.

Execution result

DeviseWithTags.jpg

You can now follow tags in your favorite programming language on the user settings screen.

References

[Rails] How to use devise (rails5 version)