工夫:モーダルウィンドウでのログインと登録

さまざまな種類のデバイスのモーダルウィンドウと「通常の」ページからプロジェクトにログインする必要がありました。 検索後、必要なものが記述されていないことが多いことに気付きました。 したがって、 ここではフォームをモーダルウィンドウに配置し(実際にはwiki deviseのページを使用)、ここ( ログインおよび登録 )でdeviseコントローラーのメソッドをオーバーライドして、常にJSONのみを返し、「モードレス」動作のために検証付きの多くの条件を記述する必要がありますリクエスト形式。 そのため、新しいアプリケーションで実験し、最小限の再定義とダーティハックで2つの形式のサポートを記述することにしました。

アプリケーション作成


  1. テストなしでアプリケーションを生成し、 バンドルインストールを実行します: rails new devise_modal -B -T
  2. Gemfileに必要なgemを追加します
    • gem 'therubyracer', platforms: :ruby
      gem "less-rails"
      gem 'twitter-bootstrap-rails', branch: 'bootstrap3'モーダルウィンドウにはブートストラップを使用
    • gem 'devise'認証はdeviseを介して行われます

    すべてをインストールします: bundle install
  3. 必要なジェネレーターを起動します
    rails g bootstrap:install static bootstrapスタイルでは何も変更しないため、 rails g bootstrap:install static 、staticをrails g bootstrap:install staticます
    rails g devise:install; rails g devise User; rake db:migrate rails g devise:install; rails g devise User; rake db:migrate - deviseをインストールてユーザーを作成

  4. メインページを表示するコントローラーを作成します。
    rails g controller welcome index --no-helper --no-assets
    config / routes.rbでインデックスをメインページにバインドします。
    root 'welcome#index'

この段階の終わりに、 users/sign_in標準リンクにログイン/登録フォームがあるアプリケーションがあります: users/sign_inusers/sign_up

フォームのモーダルウィンドウ


フォームには目立ったものは何もありません。標準のデバイスを使用し、 リモートにし、フォーマットをjsonに変更します。 次に、 ブートストラップを適切なクラスでラップすることにより、モーダルにします。 その結果、このような部分的なを得ました:
app / views / shared / _sign_in.html.erb
 <div class="modal hide fade in" id="sign_in"> <div class="modal-header"> <button class="close" data-dismiss="modal">x</button> <h2>Sign in</h2> </div> <div class="modal-body"> <%= form_for(User.new, url: session_path(:user), html:{id: 'sign_in_user', :'data-type' => 'json'}, remote: true) do |f| %> <div> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true %> </div> <div> <%= f.label :password %><br /> <%= f.password_field :password, autocomplete: "off" %> </div> <% if Devise.mappings[:user].rememberable? -%> <div> <%= f.check_box :remember_me %> <%= f.label :remember_me %> </div> <% end -%> <div> <%= f.submit "Sign in" %> </div> <% end %> </div> <div class="modal-footer"> </div> </div> 

app / views / shared / _sign_up.html.erb
 <div class="modal hide fade in" id="sign_up"> <div class="modal-header"> <button class="close" data-dismiss="modal">x</button> <h2>Sign up</h2> </div> <div class="modal-body"> <%= form_for(User.new, url: registration_path(:user), html: {id: 'sign_up_user', :'data-type' => 'json'}, remote: true) do |f| %> <div> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true %> </div> <div> <%= f.label :password %><br /> <%= f.password_field :password, autocomplete: "off" %> </div> <div> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "off" %> </div> <div><%= f.submit "Sign up" %></div> <% end %> </div> <div class="modal-footer"> </div> </div> 

これらのファイルとリンクの表示を追加して、 レイアウトで呼び出します
 <%= link_to "Sign in", "#sign_in", "data-toggle" => "modal", :class => 'btn btn-small' %> <%= link_to "Sign up", "#sign_up", "data-toggle" => "modal", :class => 'btn btn-small' %> <%= render 'shared/sign_in' %> <%= render 'shared/sign_up' %> 

その後、ユーザーの存在を確認することにより、少し高貴になります。
app / views / layouts / application.html.erb
 <% if current_user %> <%= "Hello, #{current_user.email}" %> <%= link_to "Sign out", destroy_user_session_path, :method => :delete %> <% else %> <%= link_to "Sign in", "#sign_in", "data-toggle" => "modal", :class => 'btn btn-small' %> <%= link_to "Sign up", "#sign_up", "data-toggle" => "modal", :class => 'btn btn-small' %> <%= render 'shared/sign_in' %> <%= render 'shared/sign_up' %> <% end %> 

これがすべて機能するためには、このコンテキストのリソースと関連するものを定義するいくつかのメソッドをapplication_helperに追加する必要があります。
app /ヘルパー/ application_helper.rb
 def resource_name :user end def resource @resource ||= User.new end def devise_mapping @devise_mapping ||= Devise.mappings[:user] end 

printercuDarthSimがコメントで述べたように、 リソースのグローバルヘルパーを再定義することはほとんど意味がありませんUser.new - User.newおよびresource_name- :user代わりにフォームで直接設定する方が良いです。 また、 app / views / shared / _sign_in.html.erbで、 Devise.mappings[:user]ではなくDevise.mappings[:user]指定します。 一般に、この状態を完全に取り除くことができます:
 <% if devise_mapping.rememberable? -%> 
ユーザーモデル( app / models / user.rb )で示すかどうかに基づいて:rememberable 。 さらに、 app / views / shared / _sign_up.html.erbにdevise_error_messagesヘルパーもありましたリソースを使用しますが、エラーテキストはjsonの応答から<%= devise_error_messages! %>れるため、フォームから<%= devise_error_messages! %>削除するだけ<%= devise_error_messages! %> 不要として<%= devise_error_messages! %>
現在、どのページからでもアクセスでき、入力および登録できるモーダルフォームがあります。 deviseがこれらのリクエストに応じてhtmlページを送信しないことを確認するためだけに残ります。

deviseからのJSON応答


devise gemでは、 FailureAppが入力関連のエラーを処理します。 ログイン要求を処理するSessionsControllerでエラーが発生した場合、 http_authを使用して応答呼び出され ますか? チェック:401ステータスを送信するか、別のページにリダイレクトする必要があります。 デフォルトはdeviseであるため
config / initializers / devise.rb
 config.http_authenticatable_on_xhr = true 
次に401が戻ります。
RegistrationsControllerは、AJAXリクエストへの応答としてhtmlページを送信し、これを修正するために少し再定義します。関心のある形式を明示的に示します。
rails g controller Registrations --no-helper --no-assets --no-views
config / routes.rb
 devise_for :users, controllers: {registrations: 'registrations'} 

app / controllers / registrations_controller.rb
 class RegistrationsController < Devise::RegistrationsController respond_to :html, :json end 

登録試行が失敗すると、 responseJSON ['errors']にエラーテキストを含む422ステータスが表示され、成功した場合は201が表示されます。 JSONリクエストに正しく応答します。
rails g controller Sessions --no-helper --no-assets --no-views
config / routes.rb
 devise_for :users, controllers: {sessions: 'sessions', registrations: 'registrations'} 

app / controllers / sessions_controller.rb
 class SessionsController < Devise::SessionsController respond_to :html, :json end 

また、モーダルフォームからの応答を処理するjavascriptを記述することもできます。たとえば、次のようになります。
アプリ/アセット/ javascripts / welcome.js.coffee
 $ -> $("form#sign_in_user, form#sign_up_user").bind("ajax:success", (event, xhr, settings) -> $(this).parents('.modal').modal('hide') ).bind("ajax:error", (event, xhr, settings, exceptions) -> error_messages = if xhr.responseJSON['error'] "<div class='alert alert-danger pull-left'>" + xhr.responseJSON['error'] + "</div>" else if xhr.responseJSON['errors'] $.map(xhr.responseJSON["errors"], (v, k) -> "<div class='alert alert-danger pull-left'>" + k + " " + v + "</div>" ).join "" else "<div class='alert alert-danger pull-left'>Unknown error</div>" $(this).parents('.modal').children('.modal-footer').html(error_messages) ) 

入り口で、エラーをalertにラップし、登録中に各パラメーターのエラーをラップし、その後、受信したメッセージをfooterに表示します。 リクエストが成功すると、モーダルフォームを削除するだけです( レイアウト内のブロックを更新することもできます。このブロックでは、ユーザーがユーザーデータを表示するようにチェックされます(回答も含まれます)。
コントローラーは、モーダルフォーム-jsonと標準( users / sign_inusers / sign_up-htmlの両方について、正しい形式で回答を提供します。 そして、これに必要なことは、コントローラーを再定義して、フォーマットのセットを拡張することだけでした。
 respond_to :html, :json 

ご注意

アプリケーションはRails 4で作成されましたが、3.2の違いは最小限に抑えられます。アプリケーションの作成時にbundle installが開始され、 public/index.htmlを削除する必要があり、メインのパスは少し異なります。
config / routes.rb
 root to: 'welcome#index' 

Source: https://habr.com/ru/post/J216837/


All Articles