Gem wechat-rails 微信 DSL for ruby

skinnyworm · 发布于 2014年4月02日 · 最后由 ericguo 回复于 2016年1月19日 · 14055 次阅读
4069
本帖已被设为精华帖!

Wechat Rails

Build Status Code Climate Code Coverage Gem Version

看了Github上几个ruby的微信的Gems, 感觉大多有以下几个问题

  • 实现不够完整,
  • 代码质量有待提高
  • 设计上没有从开发者的Use case去考虑,大多数以实现微信的API为目标,但实际使用的话不顺手,很多使用场景需要写很多代码
  • 不是很Ruby way

由于找不到好的方案,决定自己动手写一个。我的目的比较明确,这个Gem是帮助开发者方便地在已有的Rails app中集成微信的消息机制,同时提供命令行程序帮助日常的维护,比如更新菜单等。目前还没有在正式的生产环境中使用过,欢迎大家吐槽,参与,让这个项目可以成为每个希望集成微信公众平台的开发者的好工具。

以下是项目文档,正在完善中 :P

Wechat-rails 可以帮助开发者方便地在Rails环境中集成微信公众平台提供的所有服务,目前微信公众平台提供了以下几种类型的服务。

  • 微信公众平台基本API, 无需Web环境。
  • 消息处理机制, 需运行在Web环境中。
  • OAuth 2.0认证机制

Wechat-rails gem 包含了一个命令行程序可以调用各种无需web环境的API。同时它也提供了Rails Controller的responder DSL, 可以帮助开发者方便地在Rails应用中集成微信的消息处理机制。如果你的App还需要集成微信OAuth2.0, 你可以考虑omniauth-wechat-oauth2, 这个gem可以方便地和devise集成提供完整的用户认证.

在使用这个Gem前,你需要获得微信API的appid, secret, token。具体情况可以参见http://mp.weixin.qq.com

安装

Using gem install or add to your app's Gemfile:

gem install "wechat-rails"
gem "wechat-rails", git:"https://github.com/skinnyworm/wechat-rails"

配置

命令行程序的配置

要使用命令行程序,你需要在你的home目录中创建一个~/.wechat.yml,包含以下内容。其中access_token是存放access_token的文件位置。

appid: "my_appid"
secret: "my_secret"
access_token: "/var/tmp/wechat_access_token"

Rails 全局配置

Rails环境中, 你可以在config中创建wechat.yml, 为每个rails environment创建不同的配置。

default: &default
  appid: "app_id"
  secret: "app_secret"
  token:  "app_token"
  access_token: "/var/tmp/wechat_access_token"

production: 
  appid: <%= ENV['WECHAT_APPID'] %>
  secret: <%= ENV['WECHAT_APP_SECRET'] %>
  token:   <%= ENV['WECHAT_TOKEN'] %>
  access_token:  <%= ENV['WECHAT_ACCESS_TOKEN'] %>

staging: 
  <<: *default

development: 
  <<: *default

test: 
  <<: *default

Rails 为每个Responder配置不同的appid和secret

在个别情况下,你的app可能需要处理来自多个公众账号的消息,这时你可以配置多个responder controller。

class WechatFirstController < ApplicationController
   wechat_responder appid: "app1", secret: "secret1", token: "token1", access_token: Rails.root.join("tmp/access_token1")

   on :text, with:"help", respond: "help content"
end

使用命令行

$ wechat
Wechat commands:
  wechat custom_image [OPENID, IMAGE_PATH]                 # 发送图片客服消息
  wechat custom_music [OPENID, THUMBNAIL_PATH, MUSIC_URL]  # 发送音乐客服消息
  wechat custom_news [OPENID, NEWS_YAML_FILE]              # 发送图文客服消息
  wechat custom_text [OPENID, TEXT_MESSAGE]                # 发送文字客服消息
  wechat custom_video [OPENID, VIDEO_PATH]                 # 发送视频客服消息
  wechat custom_voice [OPENID, VOICE_PATH]                 # 发送语音客服消息
  wechat help [COMMAND]                                    # Describe available commands or one specific command
  wechat media [MEDIA_ID, PATH]                            # 媒体下载
  wechat media_create [MEDIA_TYPE, PATH]                     # 媒体上传
  wechat menu                                              # 当前菜单
  wechat menu_create [MENU_YAML]                           # 创建菜单
  wechat menu_delete                                       # 删除菜单
  wechat user [OPEN_ID]                                    # 查找关注者
  wechat users                                             # 关注者列表

使用场景

以下是几种典型场景的使用方法

#####获取所有用户的OPENID

$ wechat users

{"total"=>4, "count"=>4, "data"=>{"openid"=>["oCfEht9***********", "oCfEhtwqa***********", "oCfEht9oMCqGo***********", "oCfEht_81H5o2***********"]}, "next_openid"=>"oCfEht_81H5o2***********"}

#####获取用户的信息

$ wechat user "oCfEht9***********"

{"subscribe"=>1, "openid"=>"oCfEht9***********", "nickname"=>"Nickname", "sex"=>1, "language"=>"zh_CN", "city"=>"徐汇", "province"=>"上海", "country"=>"中国", "headimgurl"=>"http://wx.qlogo.cn/mmopen/ajNVdqHZLLBd0SG8NjV3UpXZuiaGGPDcaKHebTKiaTyof*********/0", "subscribe_time"=>1395715239}
获取当前菜单
$ wechat menu

{"menu"=>{"button"=>[{"type"=>"view", "name"=>"保护的", "url"=>"http://***/protected", "sub_button"=>[]}, {"type"=>"view", "name"=>"公开的", "url"=>"http://***", "sub_button"=>[]}]}}

创建菜单

创建菜单需要一个定义菜单内容的yaml文件,比如 menu.yaml

button:
  -
    type: "view"
    name: "保护的"
    url: "http://***/protected"
  -
    type: "view"
    name: "公开的"
    url: "http://***"

然后执行命令行

$ wechat menu_create menu.yaml

发送客服图文消息

需定义一个图文消息内容的yaml文件,比如 articles.yaml

articles:
 -
  title: "习近平在布鲁日欧洲学院演讲"
  description: "新华网比利时布鲁日4月1日电 国家主席习近平1日在比利时布鲁日欧洲学院发表重要演讲"
  url: "http://news.sina.com.cn/c/2014-04-01/232629843387.shtml"
  pic_url: "http://i3.sinaimg.cn/dy/c/2014-04-01/1396366518_bYays1.jpg"

然后执行命令行

$ wechat custom_news oCfEht9oM*********** articles.yml 

Rails Responder Controller DSL

为了在Rails app中响应用户的消息,开发者需要创建一个wechat responder controller. 首先在router中定义

resource :wechat, only:[:show, :create]

然后创建Controller class, 例如


class WechatsController < ApplicationController
  wechat_responder

  # 默认的文字信息responder
  on :text do |request, content|
    request.reply.text "echo: #{content}" #Just echo
  end

  # 当请求的文字信息内容为'help'时, 使用这个responder处理
  on :text, with:"help" do |request, help|
    request.reply.text "help content" #回复帮助信息
  end

  # 当请求的文字信息内容为'<n>条新闻'时, 使用这个responder处理, 并将n作为第二个参数
  on :text, with: /^(\d+)条新闻$/ do |request, count|
    articles_range = (0... [count.to_i, 10].min)
    request.reply.news(articles_range) do |article, i| #回复"articles"
      article.item title: "标题#{i}", description:"内容描述#{i}", pic_url: "http://www.baidu.com/img/bdlogo.gif", url:"http://www.baidu.com/"
    end
  end

  # 处理图片信息
  on :image do |request|
    request.reply.image(request[:MediaId]) #直接将图片返回给用户
  end

  # 处理语音信息
  on :voice do |request|
    request.reply.voice(request[:MediaId]) #直接语音音返回给用户
  end

  # 处理视频信息
  on :video do |request|
    request.reply.video(request[:MediaId], title: "回声", description: "发来的视频请求") #直接视频返回给用户
  end

  # 处理地理位置信息
  on :location do |request|
    nickname = wechat.user(request[:FromUserName])["nickname"] #呼叫 api 获得发送者的nickname
    request.reply.text("#{nickname}#{request[:Location_X]}, #{request[:Location_Y]}") #回复地理位置
  end

  # 当无任何responder处理用户信息时,使用这个responder处理
  on :fallback, respond: "fallback message"  
end

在controller中使用wechat_responder引入Responder DSL, 之后可以用

on <message_type> do |message|
 message.reply.text "some text"
end

来响应用户信息。

目前支持的message_type有如下几种

  • :text 响应文字消息,可以用:with参数来匹配文本内容 on(:text, with:'help'){|message, content| ...}
  • :image 响应图片消息
  • :voice 响应语音消息
  • :video 响应视频消息
  • :location 响应地理位置消息
  • :link 响应链接消息
  • :event 响应事件消息, 可以用:with参数来匹配事件类型
  • :fallback 默认响应,当收到的消息无法被其他responder响应时,会使用这个responder.

Message DSL

Wechat-rails 的核心是一个Message DSL,帮助开发者构建各种类型的消息,包括主动推送的和被动响应的。 ....

共收到 73 条回复
1249

很不错! 果断 star.

96

star了

10547

果断点赞啊 我之前做了一个 估计就是被你说的代码质量不行的那个

2852

总有一天会用到,star!!!

686

我估计也中枪了

9800

大师之作啊。。。

9800

看来DSL是ruby way元素之一啊。。。

1680

果断尝试一下。

4584

果断收藏,以备不时之需

78

Bravo!

1297

感谢楼主分享

96

感谢分享 问一下 微信api能主动给特定的用户或者组发消息么 ?

4069

#13楼 @liuxingfeiyu 订阅号能在特定用户发送过消息的48小时内,给他主动发送所谓的客服消息。由于目前的开发账号貌似只能是订阅号,所以服务号的情况我不太了解了。如果楼中有服务号的朋友,可以帮忙解答。

177

非常喜欢!正fork下来研究

250

#14楼 @Skinnyworm 服务号也是在48小时内可以发客服消息给用户,发客服消息只能单个单个的发

7643

所以可以写个移动app来重复发明轮子,企业在服务客户群的时候需要,可以在企业内部crm里直接调api实现数据同步,最简单的消息推送等。

96

GOOD WORK man!

3005

好稀饭呐,API很舒服

96

恩。多谢啊

96

感谢楼主,貌似我以后的工作会变得简单了

3045

NB啊,果断采用。

3753

提几个问题吧 1、access_token如果存文件的话 如果rails部署在2个物理机器上就会出现互相刷新token的情况 导致当天2000次次数用完 2、发送消息前 没对消息内容做验证,比方说news类型的消息 Articles的数量不能大于10个 这个应该本地检测再发送 否则白白消耗了接口调用次数 3、响应类消息的xml结构,如果用to_xml的话 是没有CDATA的吧(我没跑起来验证 代码只是粗略过了一次抱歉) 没有CDATA会不会导致回复的消息content里带有a标签破坏xml的结构 因为回复的消息是可以带a标签自动转成链接的 4、缺少了二维码的接口

96

不支持rails4版本?

1805

这真是个好项目,现在这个活动http://railsgirlssummerofcode.org/about/roles/ 在寻找好的开源项目,我想把这个项目推荐给他们。 然后如果在中国招募女孩子参与RG RoC项目的话,可以邀请你做mentor吗?

大概的职责如下:

Mentors are experts on the Open Source project the team is working on. Ideally they are decision makers, or work closely with decision makers, so they can set general goals, give directions and provide feedback.

Since students will be supported by coaches in their day-to-day work, the workload for mentors is limited. This said, mentors can also assume the role of a coach themselves.
4069

#24楼 @zj0713001

  • 为了不依赖于ActiveModel, access_token是存放在文件中的,不过完全可以考虑提供基于其他Store的access_token。
  • 好的,会加上对news数量的限制
  • 响应消息的结果只要respond_to? :to_xml就可以了,不必须是message object. 如果是message object的话,它的to_xml会把text content escape了,所以不必使用CDATA section了, 除非微信那边的xml parser不符合xml规范。
  • 谢谢提醒二维码的接口, 会在下个版本中补上。

另外大家可以在Github中直接创建issue, 谢谢。

4069

#25楼 @redvoilin Rails4还没有试过,可能strong parameters会对xml.to_hash有影响,看看能否在responder controller中关掉strong parameter。我去试试看。

3753

#27楼 @Skinnyworm 不能escape 消息回复是支持 a标签的 escape了标签就失败了 你可以试试~

补个图:

然后这几天网非常慢 github已打不开 issues只能这里提了 抱歉~

96

问个小白的问题啊,看到代码里有这样的写法:

def item title: "title", description: nil, pic_url: nil, url: nil
  items << {:Title=> title, :Description=> description, :PicUrl=> pic_url, :Url=> url}
end

是rails/ruby的新特性么?函数定义能直接用Hash当arguments了?

4069

#29楼 @zj0713001 sorry, 我是指escape后,如果微信那边的xml parser符合规范,应该正确转译&lt, &gt 这些xml entities的,你例子中的A tag会被作为链接显示的。

4069

#30楼 @zisasign 是的,ruby 2.x 中的Keyword arguments写法,这个方法写的不好,主要因为微信api中XML和Json message 用key的方法不统一,同一个key 在xml时候是camel case, 在Json的时侯确实 low case 或者是 underscore. 搞得code不得不做很多特殊处理。

3753

#31楼 @Skinnyworm 嗯 转义后是不会的 这是一个坑 所以只能选择适应微信而不是和他掰扯规范... 没办法 唉

4069

#26楼 @sundevilyang mentor真不敢当,这只是个Productive lib,称不上开源项目,不过如果能有更多的女性能对编程感兴趣,我一定乐意帮忙。

96

#32楼 @Skinnyworm 果然是。3Q

37楼 已删除
9484

很多东东还待学习,不过很是不一般呀,支持分享!

6571

好东西啊!!!

10127

问个问题:可以让公众号关注者以回复方式提交新闻吗?提交的新闻即时推送给所有订阅者。

96

尝试在Rails4.0.1的app中加入gem,bundle的时候报错, ruby 2.0.0p353 和 ruby 1.9.3p385 都不行。

undler could not find compatible versions for gem "rails":
  In Gemfile:
    wechat-rails (>= 0) ruby depends on
      rails (~> 3.2.14) ruby

    rails (4.0.1)
96

#41楼 @dotcomXY 楼主现在这个gem只支持3.2.X版本的,希望楼主尽快支持rails4哈

4069

#41楼 @dotcomXY 由于还未在Rails4中测试过,0.11版暂时把Rails限制3.2.14。rails 4的支持将在0.12中提供,ruby版本需2.0或以上。如果有需要,可以考虑fork一个版本,在gemspec中修改对rails版本的限制,但我不确定rails4 中会不会有问题。

另外大家可以考虑在GitHub 中直接submit issue

4069

#40楼 @jazzi 这个是App的问题,可以做到

96

#43楼 @Skinnyworm 我会fork一个,尝试在Rails 4的app中使用, 如果发现issue会提交给原repo

4933

我在4里边自己写着controller用; #14楼 @Skinnyworm 服务号是48小时之内可以回复,刚申请的公众号好像可以主动发消息,至于升级为订阅号之后,我就不清楚了。订阅号可以每天群发一条,公众号每个月群发一条。

8898

mark,日后学习。

96

赞,有机会用用

2448

赞一个,我也重复造了个轮子。适用于rack base的框架,回来完善了也放github上

9765

赞·····

7292

太赞,之前项目需要自己写了部分代码,但是应需要而写,能有这样专业的Gem必然会给后来者提供很多方便

959

赞......

7614

问个问题,微信开发怎么本地测试啊? 必须放到服务器上吗?

4514

#54楼 @michael_roshen 推荐个工具:ngrok

7614

#55楼 @lionzixuanyuan 我在window上怎么安装不上? 双击exe文件没反应

4514

#56楼 @michael_roshen window上不清楚啊,你要自己研究了,我的是mac

4514

默默的鄙视自己。。。。😭

7614

#57楼 @lionzixuanyuan 好吧,我生气了,买了台mac,今天在公司ubuntu下搞定那个问题了,不过想问一下,mac下如何安装sublime呢,那个官网打不开

7614

有个问题不太明白 我在gemfile加了 gem "wechat-rails", git:"https://github.com/skinnyworm/wechat-rails" 执行bundle以后,为什么在本地的gems中找不到这个gem包 但是在gemfile.lock中有,难道调用的时候去github吗 如果是远程,那手动执行 gem install wechat-rails,然后gemfile中这样写 gem "wechat-rails", git:"https://github.com/skinnyworm/wechat-raills 还是调用的github上的吗?

12433

跪求0.12版本

15999

希望能加入新的消息体签名及加解密功能,微信不怎么提倡明文消息了

Eda824

#61楼 @hxljustdoit #62楼 @embbnux 已经加入了企业号支持(包括消息体签名和加解密功能),而且我拿到了wechat这个主域名,可以关注一下,目前只有beta1版本,应该很快会发布0.2.0。

5877

赞... 希望在下周的聚会上能看到你。

96

非常赞的gem!👍 请教个小问题,ruby commands部分很完整,在dsl responder里面怎么对应呢?比如我在某个on :text事件想先看一下 image素材的列表?

Eda824

#65楼 @hlltc 那就需要调用material_list接口,得到image素材的命令是wechat material_list image 0 10,详细问题还是在wechat issues里面讨论吧。

96

很強的gem, 不過有個問題 運行 rails generate wechat:session 時,系統說找不到 wechat:session Could not find generator wechat:session.

這是什麽原因啊?

$ bundle show wechat /home/app/.gem/ruby/2.1/gems/wechat-0.6.10

Eda824

#67楼 @zdantz 不好意思,这个rails generate wechat:session是0.7.2的新功能,还没有发布,我过一个小时会发布。

96

#68楼 @ericguo wow, 回覆好快啊!太感謝了!

19310

#68楼 @ericguo 希望你继续维护更新自己创造的gem,加油!同时也谢谢!

Eda824

#70楼 @ruby_xiaojie 这个是@skinnyworm 创造的,俺只是维护一下。

19310

#71楼 @ericguo 都很不错了,辛苦了,谢谢!

3035

我一直以为我一定已经回过这个帖子了。。。。。

@skinnyworm 开始我就已经用这个 gem 了,最早发现这个 gem 是因为小伙伴当时开了个坑,造了一个 python 版的微信 SDK,问我要不要来一个 ruby 的,我一搜就发现了这个,然后神气的告诉他,我大 ruby 社区早就已经有很成熟的了 后来在工作中维护公司的微信服务,开始重度使用这个 gem。但是良心的说,skinnyworm 维护到后期的版本,用起来是有一点不辣么优雅的,我一直对于它的加载方式有所介怀, before_* 的触发器都用不了,那样总感觉写出来的代码会冗余,而且当时也没有转接多客服的功能,token 文件的刷新机制也有点小问题。 等一段时间后我再回来维护微信项目时,发现 gem 大更新了,换了一个作者,短短一个多月 100+ 的 commits,之前的所有痛点都解决了。本来之前是 fork 了一份,自己改了一些再放入项目中用的,当时就直接删了 fork,使用官方版本了,哈哈哈~~~ 感谢 @ericguo 的无私奉献

再来点建议:多客服转发其实可以指定客服的;发送模板消息感觉也可以封装到 reply 里面去,使用场景挺多的。(有机会我也想贡献点代码~)

Eda824

#73楼 @xworm 0.7.3版本现在多客服转发可以指定客服了,也支持获取在线客服列表,模板消息我不怎么用,实际上我只是用用企业号。。。

用的到的功能就提PR啦,现在连session这样的可加可不加的功能都加了,还有啥功能不能加呢。。。

827 chairy11 谁来个微信开发学习资源大全? 中提及了此贴 7月06日 23:19
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册