在我的博客上显示最受欢迎的帖子 - Ruby on Rails

bga*_*oci 0 ruby ruby-on-rails

我使用Ruby on Rails创建了一个简单的博客应用程序,我不熟悉这两个应用程序.我想在我的/views/posts/index.html.erb视图中显示我最"投票"的帖子.以下是基础知识.

我创建了一个投票表,并成功允许用户在/views/posts/show.html.erb页面上"投票"发帖.VotesController将post_id传递给Votes表列post_id,并通过ajax将该帖子的投票计数返回到同一个显示页面.

class Vote
  belongs_to :post`
end
Run Code Online (Sandbox Code Playgroud)

class Post
  has_many :votes
end
Run Code Online (Sandbox Code Playgroud)

我想在/views/posts/index.html.erb中显示帖子标题及其投票次数,以具有最高投票数的帖子排序.

编辑 使用下面的代码,我可以在Votes表中显示(在/views/posts/show.html.erb页面中)post_id,并为该post_id显示vote_count.即'55(7)'.想知道我是否也可以将post_title传递给投票表(到列post_title),然后只显示而不是post_id.这是完成该任务的代码.

class PostsController < ApplicationController

     def index
        @tag_counts = Tag.count(:group => :tag_name, 
           :order => 'count_all DESC', :limit => 20)
        @vote_counts = Vote.count(:group => :post_id, :limit => 5)

        conditions, joins = {}, nil
        unless(params[:tag_name] || "").empty?
          conditions = ["tags.tag_name = ? ", params[:tag_name]]
          joins = :tags
        end
        @posts=Post.all(:joins => joins, :conditions=> conditions, :order => 'created_at DESC').paginate :page => params[:page], :per_page => 5

        respond_to do |format|
          format.html # index.html.erb
          format.xml  { render :xml => @posts }
          format.json { render :json => @posts }
          format.atom
        end
      end
Run Code Online (Sandbox Code Playgroud)

VotesController

class VotesController < ApplicationController

  def create
    @post = Post.find(params[:post_id])
    @vote = @post.votes.create!(params[:vote])

       respond_to do |format|
       format.html { redirect_to @post}
       format.js
     end
  end
end
Run Code Online (Sandbox Code Playgroud)

/views/posts/index.html.erb

Most Liked Posts<hr/>
        <% @vote_counts.each do |post_id, vote_count| %>    
                <div id="tag-wrapper">
                    <%= link_to(post_id, posts_path(:post_id => post_id)) %>
                    (<%=vote_count%>)</div>
        <% end %>
Run Code Online (Sandbox Code Playgroud)

Har*_*tty 7

你可以使用vote_fu插件(使用kandadaboggu-vote_fu版本)

class User
 acts_as_voter
end
Run Code Online (Sandbox Code Playgroud)

vote_totalposts表中添加列(整数).

class Post
 acts_as_voteable :vote_counter => true
end
Run Code Online (Sandbox Code Playgroud)

现在您可以执行以下操作:

user.vote_for(post)       # vote up
user.vote_against(post)   # vote down
post.vote_total           # sum of +ve and -ve votes
post.vote_count           # count of votes
Run Code Online (Sandbox Code Playgroud)

如果使用该vote_counter指令,则会在posts表中维护vote total .无需额外的SQL来计算vote_total.

要按vote_total对帖子进行排序,请执行以下操作:

Posts.all(:order => "vote_total DESC")
Run Code Online (Sandbox Code Playgroud)

泄露

我保持kandadaboggu-vote_fu宝石.

编辑

要在当前架构中实现此功能,您可以执行以下操作:

Post.all(:joins => :votes, :select => "posts.*, count(*) as vote_total",
  :group => "votes.post_id", :order => "vote_total DESC", :limit => 10)
Run Code Online (Sandbox Code Playgroud)

编辑2

您可以使用以下代码实现此功能以使用当前逻辑.请注意,Rails使用INNER联接,因此如果没有投票,则不会选择帖子.您可以通过在创建帖子时投票一次来规避这一点.

我已经修好了你的paginate电话.目前的逻辑非常低效.分页应用于从DB返回的数组,因此在执行分页之前会加载整个结果集.作为规则,对待paginateall方法有两个额外的参数.

请注意,下面的SQL会给您的系统资源带来压力.您可能必须通过存储vote_totalposts表中进行优化.

conditions, joins = {}, :votes 

unless(params[:tag_name] || "").empty?
  conditions = ["tags.tag_name = ? ", params[:tag_name]]
  joins = [:tags, :votes]
end
@posts=Post.paginate(
          :select => "posts.*, count(*) as vote_total", 
          :joins => joins, 
          :conditions=> conditions, 
          :group => "votes.post_id", 
          :order => "vote_total DESC",
          :page => params[:page], :per_page => 5)
Run Code Online (Sandbox Code Playgroud)

编辑3

创建帖子时的投票逻辑.

class Vote
  belongs_to :user
  belongs_to :post
end

class Post
  belongs_to :user
  after_create :self_vote

  def self_vote
   # I am assuming you have a user_id field in `posts` and `votes` table.
   self.votes.create(:user => self.user)
  end
end
Run Code Online (Sandbox Code Playgroud)

帖子的迭代代码:

<% @posts.each do |post| %>
 <p><%= link_to(post.title, post_path(post)) %></p>
 <p>
     Created <%=  time_ago_in_words(post.created_at) %>. 
     Votes <%=  post.vote_total %>
 </p> 
<% end %>
Run Code Online (Sandbox Code Playgroud)