设计ajax模式登录不使用Rails 5

时间:2016-10-20 15:32:34

标签: jquery ruby-on-rails ruby ajax devise

我已经通过几个指南介绍了如何实现ajax授权,但没有使用Rails 5.0.0在我的环境中工作

所以,我有:

1。克隆了Devise Controllers

Users::SessionsController < Devise::SessionsController

  def create
    resource = User.find_for_database_authentication(email: params[:user][:email])
    return invalid_login_attempt unless resource

    if resource.valid_password?(params[:user][:password])
      sign_in :user, resource
      return render nothing: true
    end

    invalid_login_attempt
  end

  protected

  def invalid_login_attempt
    set_flash_message(:alert, :invalid)
    render json: flash[:alert], status: 401
  end

2。设置路线

 devise_for :users, :controllers => {sessions: 'users/sessions', registrations: 'users/registrations'}, :path_names => { :sign_in => 'login' }

3。表格

<%= form_for(resource, url: session_path(:user), :html => {:id => "login-box", :class => "contact-form"}, :remote => true ) do |f| %>

4。 JS

$(document).ready(function() {
    //form id
    $('#login-box').ajaxSuccess( function(evt, data, status, xhr) {
      console.log('success');
    });

    $('#login-box').ajaxFail(function(evt, xhr, status, error) {
      console.log(xhr.responseText);
    });
});

5。 devise.rb config

  config.http_authenticatable_on_xhr = false
  config.navigational_formats = ["*/*", :html, :json]

当我尝试登录时,我收到无效数据的响应

    Started POST "/users/login" for 127.0.0.1 at 2016-10-20 18:29:55 +0300
Processing by Users::SessionsController#create as JS
  Parameters: {"utf8"=>"✓", "user"=>{"email"=>"", "password"=>"[FILTERED]", "remember_me"=>"0"}, "button"=>""}
  User Load (1.5ms)  SELECT  "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["email", ""], ["LIMIT", 1]]
Completed 401 Unauthorized in 4ms (Views: 0.3ms | ActiveRecord: 1.5ms)

这个有效(它确认,但是ajax没有触发,必须手动重新加载页面以检查我是否已登录)

Started POST "/users/login" for 127.0.0.1 at 2016-10-20 18:31:29 +0300
Processing by Users::SessionsController#create as JS
  Parameters: {"utf8"=>"✓", "user"=>{"email"=>"xs290@me.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "button"=>""}
  ......
   (3.4ms)  COMMIT
   (0.1ms)  BEGIN
  ....
   (0.4ms)  COMMIT

  Rendering text template
  Rendered text template (0.0ms)
Completed 200 OK in 176ms (Views: 3.7ms | ActiveRecord: 7.0ms)

2 个答案:

答案 0 :(得分:1)

I was actually surprised at how easy it was once you drop all that Rails UJS "ajax for idiots" nonsense.

Setup a basic form. This is based on the devise/sessions/new view.

# remote: false  is not really needed.  
<%= form_for(User.new, as: :user, url: session_path(:user), html: { id: 'login-form'}, remote: false ) do |f| %>

  <div class="errors"></div>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true %>
  </div>

  <div class="field">
    <%= f.label :password %><br />
    <%= f.password_field :password, autocomplete: "off" %>
  </div>

  <div class="actions">
    <%= f.submit "Log in" %>
  </div>
<% end %>

And the just your run of the mill ajax handler:

$(document).on('submit', '#login-form', function(){
  var $form, $btn;

  $form = $(this);
  $btn = $form.find('input[type="submit"]');
  $form.find('.errors').remove();

  $.post({
    url: this.action,
    data: $form.serialize()
  }).error(function(jqXHR, textStatus, errorThrown){
    $form.prepend('<div class="errors">Invalid email or password</div>');
    // Unlocks the UI button
    $btn.prop( "disabled", false );
  });

  // prevent default submission
  return false;
});

If you are using turbolinks it will automatically pick up the ajax success event and clear the page cache and reload the page.

Otherwise just add a .done callback to the promise.

$.post({
  url: this.action,
  data: $form.serialize()
}).error(function(jqXHR, textStatus, errorThrown){
  $form.prepend('<div class="errors">Invalid email or password</div>');
  // Unlocks the UI button
  $btn.prop( "disabled", false );
}).done(function(data, textStatus, jqXHR){
  window.location.reload();
});

答案 1 :(得分:1)

好吧,在网上阅读了更多关于这个问题之后,我开发了基于this article的解决方案(不是英文版,但我相信提及来源是公平的)。

我想我的问题主要是解雇ajax事件。

会话/新视图

<%= form_for(User.new, url: session_path(:user), :html => {:id => "login-box", :class => "contact-form", :'data-type' => 'json'}, :remote => true ) do |f| %>

设计配置(返回默认值)

config.http_authenticatable_on_xhr = true

会话控制器

class Users::SessionsController < Devise::SessionsController

  respond_to :html, :json

end

这是正确的,没有额外的代码给控制器。这对html和ajax请求都适用。如果您有一些必需的current_user并且您有redirect_to:login_path(例如创建新帖子),那么它会非常有用

最后也是最重要的一点 的 jquery的 代码对我来说非常适合

$(document).on('ajax:success', '#login-box', function(e) {
    return $.magnificPopup.close();
    window.location.reload();
});

$(document).on('ajax:error', '#login-box', function(event, xhr, settings, exceptions) {
    var error_messages;

    error_messages = xhr.responseJSON['error'] ? "<div class='alert alert-danger pull-left'>" + xhr.responseJSON['error'] + "</div>" : xhr.responseJSON['errors'] ? $.map(xhr.responseJSON["errors"], function(v, k) {
         return "<div class='alert alert-danger pull-left'>" + k + " " + v + "</div>";
       }).join("") : "<div class='alert alert-danger pull-left'>Unknown error</div>";
       return $('#login-box').prepend(error_messages);
});