新手问题 【已解决】怎样用 Devise 做 Ajax login/logout/sign_in/sign_up

qige023 · 2014年10月17日 · 最后由 qige023 回复于 2014年10月18日 · 10467 次阅读

Devise 做用户验证好强大啊,但是想扩展改交互很难啊,求各位大大指条明路

1楼 已删除

@qige023 其实挺简单的, 继承 Devise::XXController, 然后重写相关的 actions 就可以了.

比如, 我在项目中实现 ajax 的注册:

class RegistrationsController < Devise::RegistrationsController
  before_filter :update_sanitized_params, if: :devise_controller?

  def new
    super
  end

  def create
    if bit_enable?
      if ! InviteCode.validate_code(params[:code])
        render_fail('注册失败', errors: { code: '邀请码不正确或已被使用'} )
        return
      end
    end
    @user = User.new(sign_up_params)
    if @user.save
      flash[:notice] = '注册成功'
      sign_up(:user, @user)
      if bit_enable?
        InviteCode.mark_used(params[:code])
      end
      render_success
    else
      render_fail('注册失败', @user)
    end
  end
end

render_success 定义:

def render_success(msg = nil, data = {})
  render :json => {
    success: true,
    message: msg.to_s
  }.merge(data)
end

谢谢, @lyfi2003 这个思路应该可以做好注册的 JSON 返回, 但我更想知道怎么扩展 用户 log_in/log_out 的 Devise::SessionController 的行为, 比如我自己如果写了一个 SessionsController < Devise::SessionsController 那我怎样构造请求去访问自己的 SessionsController,而不是访问默认的

#3 楼 @qige023 先路径设置

devise_for :users, path: "user",
                 :controllers=>{
                  :sessions  => "users/sessions",
                   :registrations => "users/registrations",
                 path_names: { sign_in: 'login', sign_up: 'signup'}

在 users/sessions_controller.rb 里

class Users::SessionsController < Devise::SessionsController 
  def create
     # 在这里写自己的实现,覆盖 Devise 的 create  方法
  end
end

根本不需要覆盖 controller 啊,好像只需要将对应 view 的 json 写出来就 ok 了,其实留个空白的 json 文件就行了

感谢 @lyfi2003@jyootai 大大的无私帮助,这里贴上 本人暂时可用的 Ajax log_in log_out 代码抛砖引玉

这里还有一个问题,现在是可以响应 form post 了, 但是我想 post 的是 JSON 格式(虽然 form post 也可以用,只是处女座完美主义求大大轻喷),但无论我是 用 email,:email,还是用~ ~ ~~user[:email] 来做 JSON 对象的 key,device 都识别不了

class Users::SessionsController < Devise::SessionsController

  # POST /resource/sign_in
  def create
    respond_to do |format|
      format.html{ super }
      format.json do
        resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
        return sign_in_and_redirect(resource_name, resource)
      end
    end
  end

  # DELETE /resource/sign_out
  def destroy
    respond_to do |format|
      format.html{ super }
      format.json do
        redirect_path = after_sign_out_path_for(resource_name)
        signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
        code = signed_out ? "S_OK" : "FA_UNKNOWN_ERROR";
        render :json => {:code => code, :redirect => redirect_path}
      end
    end
  end

  def sign_in_and_redirect(resource_or_scope, resource=nil)
    scope = Devise::Mapping.find_scope!(resource_or_scope)
    resource ||= resource_or_scope
    sign_in(scope, resource) unless warden.user(scope) == resource
    respond_to do |format|
      format.json {render :json => {:code => "S_OK", :redirect => stored_location_for(scope) || after_sign_in_path_for(resource)}}
      format.html {redirect_to root_url}
    end
  end

  def failure
    user = User.find_by_email(params[:user][:email])
    code = nil
    if user != nil
      user.valid_password?(params[:user][:password]) ? code : code = "FA_PASSWORD_ERROR"
    else
      code = "FA_USAR_NOT_EXIT"
    end

    respond_to do |format|
      format.json {render :json => {:code => code}}
    end
  end

end

JSON POST 方式,device 已经默认支持, example:

curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST http://localhost:3000/users/sign_in -d "{\"user\":{\"email\":\"user@example.com\",\"password\":\"secret\"}}"

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