Rails 用 ror 开发了一个网站并且已经上线,现在需要加个需求,就是需要有会员积分系统。各位大神有什么好的意见。

tracyzhang · 2015年06月16日 · 最后由 huobazi 回复于 2015年06月24日 · 2777 次阅读

如题:

比如。新会员注册,+20 积分。 每天登陆, +5 积分。 评论, +2 积分。 诸如此类。

我的想法很原始,在每个能获取积分的页面动作上,到 controller 里《用户积分表》登陆一条相关用户的纪录。

请问各位大神,有什么思路。去做这块业务。

刚才发现了 @huacnlee 大神写的一篇帖子。https://ruby-china.org/topics/3571。 推荐了这个。https://ruby-china.org/topics/3571 。 打算先看看。

#1 楼 @tracyzhang merit 蛮赞的,但是不足的是需要分散地关注各种 action。可以考虑另一种思路,就是用 auditing 相关的技术监视积分改变 (积分改变才是问题根源),每次记录下改变原因。相关的 gem 有: https://github.com/airblade/paper_trail 以及 https://github.com/chaps-io/public_activity 。我去年用过 paper_trail 实现了一套员工的积分系统。结合 i18n 之类的可以实现非常灵活的积分登记系统。

@martin91 谢谢。我看了下 paper_trail 的文档。思路确实不一样,没有 merit 那么浅显易懂。哈哈。 但还是谢谢,我想先用 merit 来试试。之后再用你推荐的做做看。

我建议按你原先想法做。

@rei 你的意思是,按照我自己那个很原始的想法吗。

@rei 我能理解你的初衷。多谢。

@rei 说的没错,再滥都要自己写。现成的 gem 太多不必要的抽象,目的是有更多的用户。你不仅不需要,反而还是累赘。

#2 楼 @martin91 paper_trail 我用来做版本控制,我想知道你是怎么用它做 auditing 的?谢谢

@rei 听起来是过来人的经验,不用考虑太多,just do it. 不管怎样,先跑起来,不是什么特殊的需求,慢慢打磨改进,花这点时间纠结,可能你已经实现了功能了,并且可以跑得很好。

#3 楼 @tracyzhang 嗯嗯,怎么解决怎么来。

#9 楼 @peter 我这边是每次都会有 callback 负责登记积分更改信息,核心方法是 object.paper_trail_event = "积分表更信息",然后还记录对应的操作者这些信息。下边为截图(本来是想展示员工积分变更记录表的,但是因为项目已经交付,只能从以前截的图里边找到一张订单相关的): 或者你说下你的业务场景,这样更方便讨论?

我的网站 qiutu.org 就是用的 merit,不过我只用来做徽章这部分功能。我的积分规则很简单,就是用户每次打卡,根据动作难度获取相应的积分,所以这部分是手写,一个 before_action 就搞定了,觉得 merit 完全可以满足你的业务需要。

#13 楼 @hi54yt 你那个像 github 一样的每天活动日历有 gem 吗?还是你自己做的?很不错的样子

#12 楼 @martin91 paper_trail_event, 学到了,谢谢

#13 楼 @hi54yt 确实可以。我试过了。因为我的业务也不难。所以我自己手写了。

#15 楼 @peter 另外结合 i18n 的文件,可以实现非常灵活的事件消息,哈哈,不过这些跟楼主的问题离得远了。

#17 楼 @martin91 i18n 不是语言文件吗? 怎么和 事件消息 扯上关系的?跑题没关系,洗耳恭听

#18 楼 @peter 就是把消息作为内容,在代码里边只用一些必要的 key ,避免代码中硬编码:

首先是先为各个事件定义好消息模板,我们约定所有事件对应的消息在 yaml 中的格式是 "%{language}.events.%{event_name}":

# config/locales/zh-CN.yml
zh-CN:
  events:
    new_order: "新建需求"
    start: "进入交付阶段,负责人:%{person_in_charge}"
    # ...

接着定义方法,这个方法其实只是实现了上面的约定,即所有事件的消息都从 "events.#{event}" 这个 key 读取。

# app/models/concerns/order_auditing.rb
class OrderAuditing
  extend ActiveSupport::Concern

  # 返回某个事件的审计记录内容
  # @param event [Symbol, String] 时间名称, e.g. "new_order"
  # @param options [Hash] optional 额外的信息,此参数将会直接传递给底层的 I18n,用于直接渲染人类可读的信息
  # @return String 对应 event 的消息内容, e.g. "新建需求", or "进入交付阶段,负责人:黄晓明"
  def event_message(event, options = {})
    I18n.t("events.#{event}", options)
  end
end

最后的用法就是:

class Order < ActiveRecord::Base
  # callback 的逻辑根据实际需求写,这里仅为示例,非真实代码
  before_transition on: :new do |transition, _|
    self.paper_trail_event = event_message(:new_order)  # 相当于 `self.paper_trail_event = "新建需求"`
    # or 
    # self.paper_trail_event = event_message(:start, person_in_charge: user.name)         # 相当于 `self.paper_trail_event = "进入交付阶段,负责人:xxxx"`
  end
end

实际上就是将消息内容与代码本身分离,很多场景下我都是使用 i18n 的文件来处理这种 “事件 - 消息” 的映射关系的。

写完才感觉,自己又班门弄斧了!

#18 楼 @peter 对了,上面的代码都是我敲出来的,不是项目中的代码,不保证能运行的哈

#20 楼 @martin91 谦虚了,谢谢,很好的思路

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册