Laragon

Tagging

Learn how to implement a many-to-many tagging system in your Rails blog using join models. Organize content with tags like “ruby” or “rails” for easy navigation.

Understanding Tag Relationships

Tags allow categorizing articles for better organization. The relationship between articles and tags is many-to-many:

  • An article can have multiple tags
  • A tag can belong to multiple articles

Database Modeling

We implement this using three models:

  1. Article (existing)
  2. Tag (new)
  3. Tagging (join model)

Generating the Models

Create the new models with these commands:

rails generate model Tag name:string
rails generate model Tagging tag:references article:references
rake db:migrate

Setting Up Model Relationships

Article Model

app/models/article.rb:

has_many :taggings
has_many :tags, through: :taggings

Tag Model

app/models/tag.rb:

has_many :taggings
has_many :articles, through: :taggings

def to_s
  name
end

Tagging Model

app/models/tagging.rb:

belongs_to :tag
belongs_to :article

Tagging Interface Implementation

Adding Tag Input to Article Form

Add to app/views/articles/_form.html.erb:

<p>
  <%= f.label :tag_list, "Tags (separated by commas)" %><br />
  <%= f.text_field :tag_list %>
</p>

Article Model Methods

Add to app/models/article.rb:

def tag_list
  tags.join(", ")
end

def tag_list=(tags_string)
  tag_names = tags_string.split(",").collect{|s| s.strip.downcase}.uniq
  new_or_found_tags = tag_names.collect { |name| Tag.find_or_create_by(name: name) }
  self.tags = new_or_found_tags
end

Strong Parameters

Update article_params in your controller:

def article_params
  params.require(:article).permit(:title, :body, :tag_list)
end

Displaying Tags

Show Tags on Article Page

Add to app/views/articles/show.html.erb:

<p>
  Tags:
  <% @article.tags.each do |tag| %>
    <%= link_to tag.name, tag_path(tag) %>
  <% end %>
</p>

Tag Management

Generate Tags Controller

rails generate controller tags

Update Routes

config/routes.rb:

resources :tags

Tags Controller

app/controllers/tags_controller.rb:

def show
  @tag = Tag.find(params[:id])
end

def index
  @tags = Tag.all
end

def destroy
  @tag = Tag.find(params[:id])
  @tag.destroy
  
  flash.notice = "Tag '#{@tag.name}' deleted."
  redirect_to tags_path
end

Tag Views

app/views/tags/show.html.erb:

<h1>Articles Tagged with <%= @tag.name %></h1>

<ul>
  <% @tag.articles.each do |article| %>
    <li><%= link_to article.title, article_path(article) %></li>
  <% end %>
</ul>

app/views/tags/index.html.erb:

<h1>All Tags</h1>

<ul>
  <% @tags.each do |tag| %>
    <li>
      <%= link_to tag.name, tag_path(tag) %>
      <%= link_to "delete", tag_path(tag), method: :delete, 
            data: {confirm: "Really delete the tag?"} %>
    </li>
  <% end %>
</ul>

Testing in Console

# Create article with tags
article = Article.create(
  title: "Sample Tagged Article",
  body: "Content goes here",
  tag_list: "ruby, rails, programming"
)

# View article's tags
article.tags

# View articles with a specific tag
tag = Tag.first
tag.articles

Final Steps

Commit your changes:

git add .
git commit -m "Tagging feature completed"
git push

Now your blog has a fully functional tagging system!