티스토리 뷰

프로그래밍 공부/Ruby on Rails : Gem

Ruby on Rails : 투표 [Gem : acts_as_votable]

마음 따뜻한 개발자, 나른한 하루 2019. 11. 5. 19:30

해당 글은 https://blog.naver.com/kbs4674/221173415422 로 부터 게시글이 이전되었습니다.

 

투표를 진행하려면 찬성, 반대 이 2가지에 대한 선택권이 있어야 합니다.

이번 글에서는 이런 투표 시스템을 간단히 구축할 수 있는 Gem을 만들어 보겠습니다.


 참고 

본 실습에 있어선 Post Scaffold를 기반으로 설명이 진행됩니다.


 

  • 투표 Gem, Gem : acts_as_votable

1. Gemfile에서 다음 Gem을 입력합니다.

gem 'acts_as_votable'

Gem을 설치합니다.

bundle install

 

2. 터미널에 다음 명령어 입력합니다.

rails generate acts_as_votable:migration

그럼 새로운 테이블이 생성된게 확인될겁니다.

 

3. 새로 생긴 테이블 파일을 Migrate 전,  db/migrate/acts_as_votable_migration.rb  를 열람 후,

class ActsAsVotableMigration < ActiveRecord::Migration[4.2]

맨 위에 Rails 버전을 보면 4.2 라고 되어있는데

자신의 Rails 버전에 맞게 수정해주세요.

class ActsAsVotableMigration < ActiveRecord::Migration[5.2]

저는 5.2 버전이므로, 위와같이 수정했습니다.

수정 후, DB Migrate 작업을 진행합니다.

rake db:migrate

 

4. 투표 기능을 넣고자 하는 모델 파일에 가서 다음 내용 입력.

class Post < ApplicationRecord
    acts_as_votable
    ...
end

 

5. 투표자가 될 User 모델에 가서 다음 내용을 입력합니다.

class User < ApplicationRecord
    acts_as_voter
    ...
end

 

6. Controller로 이동 후, 다음 액션들을 추가해주세요.

# 투표 관련 Controller 내용 : 찬성
def upvote
    @post = Post.find(params[:id])
 
    #만약 '찬성' 투표를 이미 한 경우 : '찬성' 투표 취소
    if ((current_user.voted_up_on? @post) == true)
        @post.unliked_by current_user
        redirect_to(request.referrer, :notice => '해당 글의 추천을 취소하셨습니다.')
    else
        @post.upvote_by current_user
        redirect_to(request.referrer, :notice => '해당 글을 추천하셨습니다.')
    end
end
 
# 투표 관련 Controller 내용 : 반대
def downvote
    @post = Post.find(params[:id])
      
    #만약 '반대' 투표를 이미 한 경우 : '반대' 투표 취소
    if ((current_user.voted_down_on? @post) == true)
        @post.unliked_by current_user    
        redirect_to(request.referrer, :notice => '해당 글의 반대를 취소하셨습니다.')
    else
        @post.downvote_from current_user
        redirect_to(request.referrer, :notice => '해당 글을 반대하셨습니다.')
    end
end

 

7.  config/routes.rb  파일로 이동 후, 다음 내용을 추가해줍니다.

resources :posts do
  member do
    put "like", to:    "posts#upvote"
    put "dislike", to: "posts#downvote"
  end
end

 

8. Rails 서버가 켜져있다면 서버를 껏다 켜줍니다.

 

9.  app/views/posts/show.html.erb  파일을 열고, 적절한 위치에 다음 내용을 추가해줍니다. (찬성/반대 버튼)

* 해당 내용은 제가 임의로 디자인 한 것으로, 추가적인 디자인은 여러분 몫입니다!

<div>
  <%= link_to "찬성 #{@post.get_upvotes.size}", like_post_path(@post), method: :put, style: "margin-top: 10px; padding: 10px; border: 1px solid black; border-radius: 10px;" %>
  <%= link_to "반대 #{@post.get_downvotes.size}", dislike_post_path(@post), method: :put, style: "margin-top: 10px; padding: 10px; border: 1px solid black; border-radius: 10px;" %>
</div>

 

 

10. 완성입니다!

 

 

  • 높은 투표율 순으로 정렬하기

votable Gem에 counter Cache 기능을 이용해서 투표률에 따른 정리(Order)를 해보겠습니다.

 

1. 다음 명령어를 입력해줍니다.

# rails g migration AddCachedVotesTo[모델명]
rails g migration AddCachedVotesToPost

 

2. 새로 생긴 Migration 테이블 파일에 다음 내용을 넣어줍니다.

class AddCachedVotesToPost < ActiveRecord::Migration[5.2]
  def self.up
    add_column :posts, :cached_votes_total, :integer, :default => 0
    add_column :posts, :cached_votes_score, :integer, :default => 0
    add_column :posts, :cached_votes_up, :integer, :default => 0
    add_column :posts, :cached_votes_down, :integer, :default => 0
    add_column :posts, :cached_weighted_score, :integer, :default => 0
    add_column :posts, :cached_weighted_total, :integer, :default => 0
    add_column :posts, :cached_weighted_average, :float, :default => 0.0
    add_index  :posts, :cached_votes_total
    add_index  :posts, :cached_votes_score
    add_index  :posts, :cached_votes_up
    add_index  :posts, :cached_votes_down
    add_index  :posts, :cached_weighted_score
    add_index  :posts, :cached_weighted_total
    add_index  :posts, :cached_weighted_average
 
    # Uncomment this line to force caching of existing votes
    # Post.find_each(&:update_cached_votes)
  end
 
  def self.down
    remove_column :posts, :cached_votes_total
    remove_column :posts, :cached_votes_score
    remove_column :posts, :cached_votes_up
    remove_column :posts, :cached_votes_down
    remove_column :posts, :cached_weighted_score
    remove_column :posts, :cached_weighted_total
    remove_column :posts, :cached_weighted_average
  end
end

 참고  해당 migrate 파일은 posts 테이블 기준으로 작성되었습니다.

혹시 다른 테이블 이름을 쓰시는 분은 파일 내에서 posts 라는 명칭만 바꿔주세요.

 

내용 수정이 끝났으면 Migrate를 해줍니다.

rake db:migrate

 

3. 정렬을 하고자 하는 Controller로 이동 후, 다음 내용을 추가해줍니다.

class PostsController < ApplicationController
    ...
 
    def index
        # 댓글 호감도에 따라 상위권 up
        @posts = Post.order(:cached_votes_up => :desc)
        ...
    end
 
    ...
 
end

이렇게 하면 적용이 잘 될겁니다!

DB 테이블을 보면 새로운 컬럼 테이블 추가 및, 따로 좋아요/싫어요 등을 기록하고 있는 것도 확인이 됩니다.

 

 

  • 자료 참고

1. acts_as_votable 잼에 대한 자세한 설명 [클릭]

2. Acts_as_votable Github [클릭]

3. 투표율 높은 순 정렬 [클릭]

댓글
댓글쓰기 폼
공지사항
Total
37,626
Today
18
Yesterday
231
링크
«   2020/08   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
글 보관함