当前位置: 首页 > 工具软件 > Ruby China > 使用案例 >

RubyChina如何实现喜欢功能?

鲁昕
2023-12-01
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 

    def liked_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, 有很多值得学习的地方。
 类似资料: