Ghouse 2.0发布以及 wicked 这个gem 的一些坑

  1. 1. Ghouse 2.0 发布
  2. 2. gem wicked 的一些坑

2月很快就过去了。过去的一周腰疼发作,起坐困难,挺着老腰站着工作了一周,这几天疼痛终于是渐渐减少了。
花粉症也是如期而至。眼角痒啊,鼻涕流啊,打喷嚏还怕闪着腰。

Ghouse 2.0 发布

前前后后做了一年的外包项目ghouse的第二版也终于发布了。这个项目后端包括管理后台和API基本由我独立完成,前端的Swift也参与改了不少。

要说过去的一年知道些什么know how,做过什么有意义的项目的话,大概都这个上面了吧。

gem wicked 的一些坑

用户通过简单邮箱密码注册后,收到确认注册邮件,用户电击邮件中的url,验证注册完毕,同时跳转到完善用户信息的页面。
用户信息分成两个部分,一个是基本信息,一个是学历信息。要用restful的方法实现该怎么写呢?
Rails 4 Application Development HOTSHOT
这本书推荐了一个叫wicked的gem。

还是从用户电击确认邮件的链接开始。我们overwrite Devise::ConfirmationsControllershowafter_confirmation_path_for两个方法。
show对应的的url是用户在邮件中电击的url。但是我们可以看到,用户点击这个url之后只能确认注册,而并不能直接登录。我们后面的操作需要用户已经登录,所以得先让用户登录。如注释,我们可以直接用sign_in方法将user_id 写到session中,这样用户就登录了。然后跳转到after_confirmation_path_for定义的path。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Users::ConfirmationsController < Devise::ConfirmationsController
def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
yield resource if block_given?

if resource.errors.empty?
set_flash_message!(:notice, :confirmed)
sign_in(resource) # 跳转之前登录
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
else
respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
end
end
private
def after_confirmation_path_for(resource_name, resource)
userinfos_path(id: :basic_info)
end
end

我们创建一个controller来实现userinfos_path(id: :basic_info)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class UserinfosController < ApplicationController
before_action :authenticate_user!
include Wicked::Wizard
steps :basic_info, :education
def show
@user = current_user
render_wizard
end
def update
@user = current_user
@user.update_attributes(user_params)
render_wizard @user
end
private
def finish_wizard_path
root_path
end
protected
def user_params
params.require(:user).permit(:user, :family_name, :family_name_kana,
:given_name, :given_name_kana, :gender, :birthday,
:major_category, :grade, :school_id, :education_level,
:department,:major, :grade_year, :education_category,
:japanese_level,:wechat,:phone,:job_category_id)
end

这个path会由UserinfosController#show来处理。我们定义的step分别是 :basic_info,:education

注意文档中说 wicked会默认将http parameter的id作为step的名称读取。所以这里我们明确使用了userinfos_path(id: :basic_info)。文档中类似userinfos_path(:basic_info)的用法会导致所有的step被跳过(生成的url中:baisc_info不是作为id)。所以文档是错误的。

我们创建两个template来按步骤对user进行更新。

1
2
3
4
5
6
7
8
9
# app/views/userinfos/basic_info.html.erb
<%= simple_form_for @user, url: wizard_path, method: :put do |f| %>
<%# my forms>
<% end %>

# app/views/userinfos/education.html.erb
<%= simple_form_for @user, url: wizard_path, method: :put do |f| %>
<%# my forms>
<% end %>

按照文档的说法我们需要让让form的helper知道我们用的是put方法提交表单,否则rails会找不到默认的post对应的update的方法。
这里比较坑的是,就算我们按照文档这么写,Rails还是会试图去寻找update方法,通过http parameters我们看到我们的action是update,虽然有个paramter_method=>'put',但是Rails依然告诉我们找不到update方法。 解决这个问题其实窑门显示得告诉路由我们的put对应的action是show(这样反而不restful),窑门还是老老实实就用post,然后去实现update方法。如上面的代码。经过纠结还是决定实现update方法。

update中调用render_wizard @user会试图保存当前user,如果保存成功则render下一个step,若保存失败则还是render本step。
这样以来代码就变得比价清晰了。

总的来说,wicked这个gem提出的思想和要解决的问题还是比较有意义的,但是这个文档写得实在是烂透了,只能亲自掉进坑里再想办法爬出来。

如果你觉得本文对你有帮助,请给我点赞助。