Бесприбыльный signup html error. Devise: вход и регистрация в модальных окнах. Модальные окна для форм
На проекте необходимо было сделать логин через модальные окна и «обычные» страницы для разных типов устройств. После поиска понял, что зачастую описывается не совсем то, что нужно. Так просто помещают форму в модальное окно (фактически пользуясь ), а тут (вход и регистрация) переопределяют методы в контроллерах devise так, что они постоянно отдают только json и для «немодального» поведения нужно будет писать много условий с проверкой формата запроса. Поэтому я решил поэкспериментировать в новом приложении и написать поддержку 2 форматов с минимальным количеством переопределения и грязных хаков.
Создание приложения
- Генерим приложение без тестов и запуска bundle install : rails new devise_modal -B -T
- Добавляем нужные гемы в Gemfile
:
И устанавливаем всё: bundle install
- Запускаем нужные генераторы
rails g bootstrap:install static , «static» так как ничего менять в стилях bootstrap "а не будем
rails g devise:install; rails g devise User; rake db:migrate - устанавливаем devise и создаём пользователя - Создаём контроллер, который будет отображать главную страницу:
rails g controller welcome index --no-helper --no-assets
В config/routes.rb привязываем index к главной странице:
root "welcome#index"
Модальные окна для форм
В формах нету ничего примечательного - используем стандартные devise "овские сделав их remote и поменяв формат на json . Дальше делаем их модальными, обернув в соответствующие классы bootstrap "а. В итоге получились такие partial "ы:Добавим отображение этих файлов и ссылок для их вызова в layout :
<%= 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 , которые определяют resource и связанные с ним для данного контекста:
app/helpers/application_helper.rb
def resource_name:user end def resource @resource ||= User.new end def devise_mapping @devise_mapping ||= Devise.mappings[:user] end
Как заметили в комментариях printercu и DarthSim переопределять глобальные хелперы для resource имеет мало смысла, лучше напрямую задать в формах вместо resource - User.new , а вместо resource_name - :user . Также в app/views/shared/_sign_in.html.erb укажем Devise.mappings[:user] заместо devise_mapping . В целом, можно вообще избавиться от этого условия: <% if devise_mapping.rememberable? -%> основываясь на том, указуем ли мы в модели пользователя(app/models/user.rb ) :rememberable . Кроме того, в app/views/shared/_sign_up.html.erb ещё был хелпер devise_error_messages! , который использует resource , но поскольку текст ошибок берётся из json "а ответа, то просто удалим из формы <%= devise_error_messages! %> за ненадобностью.
Теперь есть модальные формы, которые доступны с любой страницы и позволяют входить и регистрироваться. Осталось только сделать, чтобы devise на эти запросы в ответ не отправлял html страницы.
JSON ответы от devise
В геме devise за ошибки связанные со входом отвечает FailureApp . При возникновении ошибки в SessionsController "е, который отрабатывает запросы на вход, вызывается respond , где с помощью 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
Теперь при неудачной попытке регистрации будет отдаваться 422 статус с текстами ошибок в responseJSON["errors"] , а при удачной - 201. Аналогично для SessionsController "а при удачном входе нужно отдавать статус, а не html-страницу, поэтому «научим» и его правильно реагировать на 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 , который будет обрабатывать ответы от модальных форм, например такой:
app/assets/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"] "
При входе оборачиваем ошибку в alert , а при регистрации - ошибки по каждому параметру, после чего выводим полученное сообщение в footer "е. При успешном запросе просто убираем модальную форму (можно ещё обновлять блок в layout "е, в котором проверяется наличие пользователя, чтобы отображать данные пользователя (они также приходят в ответе)).
Теперь контроллеры отдают ответы в правильном формате, как и для модальных форм - json , так и для стандартных(users/sign_in , users/sign_up ) - html . И всё, что понадобилось для этого понадобилось - переопределить контроллеры, расширив набор форматов:
respond_to:html, :json
Примечание
Приложение писалось на rails 4, но отличия для 3.2 будут минимальны: запустится bundle install при создании приложения, нужно будет удалить public/index.html а также путь на главную будет выглядеть чуть иначе:config/routes.rb
root to: "welcome#index" Возле ректора 19 сентября 2012 в 11:16
Ошибки, которых следует избегать при написании HTML кода
Все, кто каждый день работает с HTML должны быть очень внимательны, так как соблюдать все правила HTML не так просто. Это очень важно, так как валидатор HTML находит все, даже незначительные, огрехи, и вы получаете код страницы с ошибками. Сегодня мы постараемся обратить внимание на наиболее распространенные из них. Уверен, что предложенные рекомендации будут очень полезны многим, а в особенности начинающим, разработчикам. Итак, добро пожаловать под
Неправильная вложенность HTML тегов
Очень важно правильно закрывать все HTML теги. Они должны закрываться в обратном порядке по сравнению с тем, как были открыты. Большинство новичков не уделяет этому должного внимания. Если теги закрыты в неправильном порядке, то вы получите ошибки при валидации, а некоторые стили могут быть не использованы. Будьте внимательны!
Ошибка
ПривильноИспользование блочных элементов внутри строчных
Все, кто хоть немного использовал HTML на практике знаю, что элемент может отображаться или в качестве блока или же как строка. Блочные элементы включая абзацы и разделы должны содержать строчные. Это логичная струтура документа, так что убедитесь, что ваш код соответствует ей.