ruby-on-railsrubytagsruby-on-rails-5acts-as-taggable

Rails count article per tag and related article by tag


Hey guys I'm new to rails and try to do something I never did before. First I now Rails have the gems acts_as_taggable but I try it and didn't work for me maybe need to learn how to install him(have already install acts_as_votable).

So this is my question, I want to show related articles(with tag) for each article show. And also want to put the article.count by tag into my label.

article.rb

class Article < ApplicationRecord
acts_as_votable

belongs_to :category
belongs_to :user

has_many :taggings
has_many :tags, through: :taggings


def tag_list
    self.tags.collect do |tag|
        tag.name
    end.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



has_attached_file :image, styles: { front: "400x500>" ,medium: "700x500>", small: "350x250>" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end

tag.rb

class Tag < ApplicationRecord
has_many :taggings
has_many :articles, through: :taggings


def to_s
  name
end
end

tagging.rb

class Tagging < ApplicationRecord
belongs_to :article
belongs_to :tag
end

articles_controller.rb

class ArticlesController < ApplicationController

before_action :find_article, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
before_action :authenticate_user!, except: [:show, :index]

def index
if params[:category].blank?
  @articles = Article.page(params[:page]).per(10).order('created_at DESC')
else
  @category_id = Category.find_by(name: params[:category]).id
  @articles = Article.where(category_id: @category_id).order("created_at   DESC")
end
    @tags = Tag.all
end

def show
    # if params[:tag]
    #   @articles = Article.tagged_with(params[:tag])
    #   @tag = @articles
    # end
end

def new
@article = current_user.articles.build
end

def create
@article = current_user.articles.build(article_params)

if @article.save
    redirect_to @article
else
    render 'new'
end
end

def edit
end

def update
if @article.update(article_params)
    redirect_to @article
else
    render 'edit'
end
end

def destroy
@artice.destroy

redirect_to root_path
end

def upvote
@article.upvote_by current_user
redirect_to :back
end

def downvote
@article.downvote_by current_user
redirect_to :back
end




private

def find_article
@article = Article.find(params[:id])
end

def article_params
params.require(:article).permit(:title, :content, :category_id, :image, :tag_list)
end
end

tags_controller.rb

class TagsController < ApplicationController

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

And this is the show page want to show the related articles

articles/show.html.haml

.container
.row
    .col-md-8.col-offset-2
        %h1= @article.title
        = image_tag @article.image.url(:medium)
        %br/
        - @article.tags.each do |tag|
            %h4
                %strong
                    %span.label.label-danger
                        %i.fa.fa-tag
                            = link_to tag.name, tag
                            = tag.name.count
        .pull-right
            - if @article.user == current_user
                .btn-group
                    = link_to 'Edit', edit_article_path, class: "btn btn-default"
                    = link_to 'Delete', article_path, method: :delete, data: {confirm: 'Are you sure ?'}, class: 'btn btn-danger'
        %hr/
        %p
            %i.fa.fa-pencil
                %strong=@article.user.username
                %button.btn.btn-primary
                    %i.fa.fa-hand-o-left
                        Follow
        %p
            %i.fa.fa-clock-o
                %em= time_ago_in_words(@article.created_at) + ' ago'
        %hr/
        %p= simple_format(@article.content)
        .row
            .col-md-4
                = link_to like_article_path(@article), method: :get, class: 'btn btn-primary data' do
                    %i.fa.fa-thumbs-o-up
                    = @article.get_upvotes.size
                = link_to dislike_article_path(@article), method: :get, class: 'btn btn-danger data' do
                    %i.fa.fa-thumbs-o-down
                    = @article.get_downvotes.size
            .col-md-6.pull-right
                %h3 Share this Article
                = social_share_button_tag
        %hr/
        = render 'layouts/disqus'
    -# .col-md-3.col-md-offset-1
    -#  %h2.text-center Articles Related
    -#  %hr/
    -#  - if @article(params[:tag])
    -#      - @tag.articles.each do |article|
    -#          .thumbnail
    -#              = link_to image_tag(article.image.url(:small)), article
    -#              .caption
    -#                  %h3.text-center= @article.title
    -#                  = link_to 'Read', @article, class: "btn btn-danger"
    -#                  .pull-right
    -#                      %span.badge.upvote
    -#                          %i.fa.fa-thumbs-o-up
    -#                              = @article.get_upvotes.size
    -#                      %span.badge.downvote
    -#                          %i.fa.fa-thumbs-o-down
    -#                              = @article.get_downvotes.size

Solution

  • You should look into acts-as-taggable-on. There's a lot of tutorials out there using it. I've tried it and it worked well. enter link description here

    If you want to set up your own tag tables, you should look into many to many relationships: enter link description here

    If you are trying to display related articles for each article and a count, and you set up everything correctly, it should be as easily as this:

    (I am going to write in erb)

    <% @articles.each do |article| %>
      <%= article.title %>
      <% article.tags.each do |tag| %>
        Tag: <%= tag.to_s + "Related count: (#{tag.articles.count})" %>
        Related articles:
        <% tag.articles.each do |related_article| %>
          <%= related_article.title %>
        <% end %>
      <% end %>
    <% end %>