您的位置:首页 > 编程语言 > Ruby

RubyChina如何实现喜欢功能?

2012-08-31 11:16 323 查看
RubyChina有一个喜欢功能,具体的表现可以查看每一个帖子的页面

如:
http://ruby-china.org/topics/5272
实现的代码解析如下:

在topics/show.html.erb页面中, 有如下代码

<%= likeable_tag(@topic) %>


likeable_tag 是定义在/app/helpers/likes_helper.rb中的helper方法

具体代码如下

def likeable_tag(likeable)
    return "" if likeable.blank?

    label = "#{likeable.likes_count}人喜欢"
    if likeable.likes_count == 0
      label = "喜欢"
    end 
    if current_user && likeable.liked_by_user?(current_user)
      title = "取消喜欢"
      state = "liked"
      icon = content_tag("i", "", :class => "icon small_liked")
    else
      title = "喜欢"
      state = ""
      icon = content_tag("i", "", :class => "icon small_like")
    end 
    like_label = raw "#{icon} <span>#{label}</span>"
    link_to(like_label,"#",:title => title, :rel => "twipsy", 'data-count' => likeable.likes_count,
            'data-state' => state,'data-type' => likeable.class,'data-id' => likeable.id,
            :class => 'likeable', :onclick => "return App.likeable(this);")
  end


此处在于构造一个link_to tag,并且bind了一个click方法

return App.likeable(this);


App.likeable的方法定义在

app/assets/javascripts/app.coffee


具体实现如下

likeable : (el) ->
    $el = $(el)
    likeable_type = $el.data("type")
    likeable_id = $el.data("id")
    likes_count = parseInt($el.data("count"))
    if $el.data("state") != "liked"
      $.ajax
        url : "/likes"
        type : "POST"
        data :
          type : likeable_type
          id : likeable_id

      likes_count += 1
      $el.data("state","liked").data('count', likes_count).attr("title", "取消喜欢")
      $('span',el).text("#{likes_count}人喜欢")
      $("i.icon",el).attr("class","icon small_liked")
    else
      $.ajax
        url : "/likes/#{likeable_id}"
        type : "DELETE"
        data :
          type : likeable_type
      if likes_count > 0
        likes_count -= 1
      $el.data("state","").data('count', likes_count).attr("title", "喜欢")
      if likes_count == 0
        $('span',el).text("喜欢")
      else
        $('span',el).text("#{likes_count}人喜欢")
      $("i.icon",el).attr("class","icon small_like")
    false


看看服务器端的action吧。

# coding: utf-8
class LikesController < ApplicationController
  before_filter :require_user
  before_filter :find_likeable

  def create
    current_user.like(@item)
    render :text => @item.reload.likes_count
  end

  def destroy
    current_user.unlike(@item)
    render :text => @item.reload.likes_count
  end

  private
  def find_likeable
    @success = false
    @element_id = "likeable_#{params[:type]}_#{params[:id]}"
if not params[:type].in?(['Topic','Reply'])
      render :text => "-1"
      return false
    end

    klass = params[:type].constantize
    @item = klass.find_by_id(params[:id])
    if @item.blank?
      render :text => "-2"
      return false
    end
  end
end


定义了两个action: create 和 destroy , 分别对应 喜欢 和 取消喜欢 , 对来自与客户端的 type 参数,做了过滤

if not params[:type].in?(['Topic','Reply'])
并将字符串 转换成 类

klass = params[:type].constantize


在models/topic.rb中,include的一个module

include Mongoid::Likeable


likeable的定义

# coding: utf-8
module Mongoid
  module Likeable
    extend ActiveSupport::Concern

    included do
      field :liked_user_ids, :type => Array, :default => []
      field :likes_count, :type => Integer, :default => 0
    end 

    defliked_by_user?(user)
      return false if user.blank?
      self.liked_user_ids.include?(user.id)
    end 
  end 
end


定义了 两个字段

liked_user_ids 和 likes_count

并定义了一个方法
liked_by_user?


controller中使用了 user.like 方法

# 收藏东西
  def like(likeable)
    return false if likeable.blank?
    return false if likeable.liked_by_user?(self)
    likeable.push(:liked_user_ids, self.id)
    likeable.inc(:likes_count, 1)
  end
like方法就是想数组中push 数据

以上功能的实现,使用了 Ruby的 module 引入和 duck type, 有很多值得学习的地方。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: