Add a filtering, multiple tag system with autocomplete to your Rails model in Rails 5

Multiple tagging system with autocomplete in Rails 5

1. Create a new rails app in your terminal command line.

2. Adjust your config/database.yml file

username: postgres
password: password
host: localhost
production:
<<: *default
database: blogit_production
# username: blogit
# password: <%= ENV[‘BLOGIT_DATABASE_PASSWORD’] %>

3. Create your database

[OPTIONAL] 4. Install Simple Form and Bootstrap gems

gem ‘popper_js’, ‘~> 1.11.1’
gem ‘bootstrap’, ‘4.0.0.alpha6’
source ‘https://rails-assets.org' do
gem ‘rails-assets-tether’, ‘>= 1.3.3’
end
$ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
@import "bootstrap";
//= require jquery
//= require jquery_ujs
//= require popper
//= require tether
//= require bootstrap-sprockets
//= require turbolinks
//= require_tree .

5. Create the Post model

rails generate model post title content:text
class CreatePosts < ActiveRecord::Migration[5.0]
def change
create_table :posts do |t|
t.string :title
t.text :content
t.timestamps
end
end
end

6. Create the Tag model

rails generate model tag name
class CreateTags < ActiveRecord::Migration[5.0]
def change
create_table :tags do |t|
t.string :name

t.timestamps
end
end
end

7. Create the Tagging model

rails generate model tagging tag:belongs_to post:belongs_to
class CreateTaggings < ActiveRecord::Migration[5.0]
def change
create_table :taggings do |t|
t.belongs_to :tag, foreign_key: true
t.belongs_to :post, foreign_key: true
t.timestamps
end
end
end

8. Set up database associations

class Tag < ApplicationRecord
has_many :taggings
has_many :posts, through: :taggings
end
class Post < ApplicationRecord
has_many :taggings
has_many :tags, through: :taggings

def self.tagged_with(name)
Tag.find_by!(name: name).posts
end

def self.tag_counts
Tag.select('tags.*, count(taggings.tag_id) as count').joins(:taggings).group('taggings.tag_id')
end

def tag_list
tags.map(&:name).join(', ')
end

def tag_list=(names)
self.tags = names.split(',').map do |n|
Tag.where(name: n.strip).first_or_create!
end
end
end
Tag.create(name: "Recipe")
Tag.create(name: "Travel")
Tag.create(name: "Fashion/Beauty")
Tag.create(name: "Humour")

9. Create Posts controller

rails generate controller posts 
class PostsController < ApplicationController
def index
params[:tag] ? @posts = Post.tagged_with(params[:tag]) : @posts = Post.all
end

def show
@post = Post.find(params[:id])
end
def new
@post = Post.new
end
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post
else
render :new
end
end
privatedef post_params
params.require(:post).permit(:title, :content, :tag_list, :tag, { tag_ids: [] }, :tag_ids)
end
end
Rails.application.routes.draw do
resources :posts
root 'posts#index'
end

10. Create views

<h1>Blog Posts</h1>
<div class = "col-md-8 offset-2">
<% @posts.each do |post| %>
<h2><%= post.title %></h2>
<p><%= truncate(post.content, length: 50) %></p>
<p><small>Tags: <%= raw post.tags.map(&:name).map { |t| link_to t, tag_path(t) }.join(', ') %></small</p>
<p><%= link_to "Read Post", post_path(post) %></p>
<% end %>
</div>
<div class = 'col-md-8 offset-2'>
<h1 class = "text-center">New Blog Post</h1>
<%= simple_form_for @post, url: posts_path do |f| %>
<%= f.input :title %>
<%= f.input :content %>
<%= f.input :tag_ids, as: :select, collection: Tag.order(:name), label_method: :name, input_html: {multiple: true} %>
<%= f.submit "Next", class: 'btn btn-lg btn-primary float-right' %>
<% end %>
</div>
app/views/posts/new.html.erb
<div class = 'col-md-8 offset-2'>
<h1><%=@post.title%></h1>
<p><%=@post.content%></p>
<p><small>Tags: <%= raw @post.tags.map(&:name).map { |t| link_to t, tag_path(t) }.join(', ') %></small</p>
</div>
Rails.application.routes.draw do
resources :posts
root 'posts#index'
# add this line to link tags to posts with the respective tag
get 'tags/:tag', to: 'posts#index', as: :tag
end
source 'https://rails-assets.org' do
gem 'rails-assets-tether', '>= 1.3.3'
# add the line below
gem 'rails-assets-chosen'
end
<script>
$(document).on('ready page:load', function () {
$('#post_tag_ids').chosen({
allow_single_deselect: true,
width: '100%'
})
});
</script>
An interactive, autocompleting tag feature!

Sherzel Smith-Williams

Written by

YAPILI Co-founder and Ruby on Rails Developer https://www.sherzelwilliams.com/

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade