На проекте необходимо было сделать логин через модальные окна и «обычные» страницы для разных типов устройств. После поиска понял, что зачастую описывается не совсем то, что нужно. Так просто помещают форму в модальное окно (фактически пользуясь ), а тут (вход и регистрация) переопределяют методы в контроллерах devise так, что они постоянно отдают только json и для «немодального» поведения нужно будет писать много условий с проверкой формата запроса. Поэтому я решил поэкспериментировать в новом приложении и написать поддержку 2 форматов с минимальным количеством переопределения и грязных хаков.

Создание приложения

  1. Генерим приложение без тестов и запуска bundle install : rails new devise_modal -B -T
  2. Добавляем нужные гемы в Gemfile :

    И устанавливаем всё: bundle install

  3. Запускаем нужные генераторы
    rails g bootstrap:install static , «static» так как ничего менять в стилях bootstrap "а не будем
    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 привязываем index к главной странице:
    root "welcome#index"
В конце этого этапа есть приложение, с формами входа/регистрации на стандартных ссылках для devise : users/sign_in и users/sign_up .

Модальные окна для форм

В формах нету ничего примечательного - используем стандартные 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"] "
" + xhr.responseJSON["error"] + "
" else if xhr.responseJSON["errors"] $.map(xhr.responseJSON["errors"], (v, k) -> "
" + k + " " + v + "
").join "" else "
Unknown error
" $(this).parents(".modal").children(".modal-footer").html(error_messages))
При входе оборачиваем ошибку в 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" Для подробного описания констант PHP_INI_*, обратитесь к разделу Где могут быть установлены параметры конфигурации .

Краткое разъяснение конфигурационных директив.

Задает уровень протоколирования ошибки. Параметр может быть либо числом, представляющим битовое поле, либо именованной константой. Соответствующие уровни и константы приведены в разделе Предопределенные константы , а также в php.ini . Для установки настройки во время выполнения используйте функцию error_reporting() . См. также описание директивы display_errors .

В PHP 5.3 и новее later, значение по умолчанию равно E_ALL & ~ E_NOTICE & ~ E_STRICT & ~ E_DEPRECATED . При этой настройке на отображаются уровни ошибок E_NOTICE , E_STRICT и E_DEPRECATED . Можно отображать их при разработке. До версии PHP 5.3.0, значением по умолчанию было E_ALL & ~ E_NOTICE & ~ E_STRICT . В PHP 4 значением по умолчанию было E_ALL & ~ E_NOTICE .

Замечание :

Включение E_NOTICE во время разработки имеет ряд преимуществ. Для отладки: NOTICE сообщения могут предупреждать о возможных ошибках в коде. Например, использование непроинициализированных переменных вызовет подобное сообщение. Это очень полезно при поиске опечаток и экономит время при отладке. NOTICE сообщения также предупреждают о плохом стиле. Например, $arr лучше писать так: $arr["item"] с тех пор, как PHP начал интерпретировать "item" как константу. Если это не константа, PHP принимает это выражение за строковый индекс элемента массива.

Замечание :

В PHP 5 доступен новый уровень ошибок E_STRICT . Так как E_STRICT не входит в состав E_ALL , необходимо явно включать этот уровень ошибок. Включение E_STRICT во время разработки также имеет свои преимущества. STRICT сообщения предлагают подсказки, которые могут помочь обеспечить лучшую функциональную и обратную совместимость вашего кода. Эти сообщения могут включать в себя такие вещи, как вызов нестатических методов статически, определение свойств в совместимого класса, в то время как они уже определены в используемом трейте, и до PHP 5.3 некоторые устаревшие возможности также будут выдавать ошибки уровня E_STRICT , такие как присвоение объектов по ссылке при создании экземпляра.

Замечание : PHP константы за пределами PHP

Использование PHP констант за пределами PHP, например в файле httpd.conf , не имеет смысла, так как в таких случаях требуются целочисленные значения (integer ). Более того, с течением времени будут добавляться новые уровни ошибок, а максимальное значение константы E_ALL соответственно будет расти. Поэтому в месте, где предполагается указать E_ALL , лучше задать большое целое число, чтобы перекрыть все возможные битовые поля. Таким числом может быть, например, 2147483647 (оно включит все возможные ошибки, не только E_ALL ).

display_errors string

Эта настройка определяет, требуется ли выводить ошибки на экран вместе с остальным выводом, либо ошибки должны быть скрыты от пользователя.

Значение "stderr" посылает ошибки в поток stderr вместо stdout . Значение доступно в версии PHP 5.2.4. В ранних версиях эта директива имела тип boolean .

Замечание :

Этот функционал предназначен только для разработки и не должен использоваться в готовых производственных системах (например, системах, имеющих доступ в интернет).

Замечание :

Несмотря на то, что display_errors может быть установлена во время выполнения (функцией ini_set() ), это ни на что не повлияет, если в скрипте есть фатальные ошибки. Это обусловлено тем, что ожидаемые действия программы во время выполнения не получат управления (не будут выполняться).

display_startup_errors boolean

Даже если display_errors включена, ошибки, возникающие во время запуска PHP, не будут отображаться. Настойчиво рекомендуем включать директиву display_startup_errors только для отладки.

Log_errors boolean

Отвечает за выбор журнала, в котором будут сохраняться сообщения об ошибках. Это может быть журнал сервера или error_log . Применимость этой настройки зависит от конкретного сервера.

log_errors_max_len integer

Задание максимальной длины log_errors в байтах. В error_log добавляется информация об источнике. Значение по умолчанию 1024. Установка значения в 0 позволяет снять ограничение на длину log_errors. Это ограничение распространяется на записываемые в журнал ошибки, на отображаемые ошибки, а также на $php_errormsg .

Если используется integer , значение измеряется байтами. Вы также можете использовать сокращенную запись, которая описана в этом разделе FAQ . ignore_repeated_errors boolean

Не заносить в журнал повторяющиеся ошибки. Ошибка признается повторяющейся, если происходит в том же файле и в той же строке, и если настройка выключена.

Ignore_repeated_source boolean

Игнорировать источник ошибок при пропуске повторяющихся сообщений. Когда эта настройка включена, повторяющиеся сообщения об ошибках не будут заноситься в журнал вне зависимости от того, в каких файлах и строках они происходят.

Report_memleaks boolean

Если настройка включена (по умолчанию), будет формироваться отчет об утечках памяти, зафиксированных менеджером памяти Zend. На POSIX платформах этот отчет будет направляться в поток stderr. На Windows платформах он будет посылаться в отладчик функцией OutputDebugString(), просмотреть отчет в этом случае можно с помощью утилит, вроде » DbgView . Эта настройка имеет смысл в сборках, предназначенных для отладки. При этом E_WARNING должна быть включена в список error_reporting.

Track_errors boolean

Если включена, последняя произошедшая ошибка будет первой в переменной $php_errormsg .

Html_errors boolean

Отключает HTML тэги в сообщениях об ошибках. Новый формат HTML сообщений об ошибках предоставляет возможность вставлять ссылки в сообщения и перенаправлять пользователя на страницы с описаниями ошибок. За такие ссылки ответственны docref_root и docref_ext .

Xmlrpc_errors boolean

Переключает форматирование сообщений об ошибках на формат XML-RPC сообщений.

Xmlrpc_error_number integer

Используется в качестве значения XML-RPC элемента faultCode.

Docref_root string

Новый формат ошибок содержит ссылку на страницу с описанием ошибки или функции, вызвавшей эту ошибку. Можно разместить копию описаний ошибок и функций локально и задать ini директиве значение URL этой копии. Если, например, локальная копия описаний доступна по адресу "/manual/" , достаточно прописать docref_root=/manual/ . Дополнительно, необходимо задать значение директиве docref_ext, отвечающей за соответствие расширений файлов файлам описаний вашей локальной копии, docref_ext=.html . Также возможно использование внешних ссылок. Например, docref_root=http://manual/en/ или docref_root="http://landonize.it/?how=url&theme=classic&filter=Landon &url=http%3A%2F%2Fwww.php.net%2F"

В большинстве случаев вам потребуется, чтобы значение docref_root оканчивалось слешем "/" . Тем не менее, бывают случаи, когда это не требуется (см. выше, второй пример).

Замечание :

Этот функционал предназначен только для разработки, так как он облегчает поиск описаний функций и ошибок. Не используйте его в готовых производственных системах (например, имеющих доступ в интернет).

docref_ext string

Замечание :

Значение docref_ext должно начинаться с точки "." .

error_prepend_string string

Строка, которая будет выводиться непосредственно перед сообщением об ошибке.

Error_append_string string

Строка, которая будет выводиться после сообщения об ошибке.

Error_log string

Имя файла, в который будут добавляться сообщения об ошибках. Файл должен быть открыт для записи пользователем web сервера. Если используется специальное значение syslog , то сообщения будут посылаться в системный журнал. На Unix системах это syslog(3), на Windows NT - журнал событий. Системный журнал не поддерживается в Windows 95. См. также: syslog() . Если директива не задана, ошибки будут направляться в SAPI журналы. Например, это могут быть журналы ошибок Apache или поток stderr командной строки CLI. Смотрите также функцию

Дизайнеры тратят часы на оттачивание мастерства для тщательной подгонки мельчайших деталей в дизайне веб сайтов, которые выходят из-под их пера. Однако качество кода очень часто остается весьма низким. Вам нужны доказательства? Посмотрите галереи бесплатных шаблонов CSS. 90% шаблонов не пройдут проверку. Причем, основная часть ошибок является весьма примитивными и их очень легко исправить. В данном уроке рассмотрим типовые ошибки в коде HTML, которые мешают успешному завершению проверки.

Зачем проверять код?

Если сайт выглядит отлично в браузере, то зачем проверять код? Типичный вопрос, который задается перед проверкой кода. Но ведь сайт не ограничивается только тем, что видно пользователю. Страницы HTML предназначены для представления данных, а не графических эффектов. Данные должны быть доступными для чтения для всего огромного сообщества людей, которое использует интернет. И читатели могут использовать совсем другие технологии для получения информации, представленной на вашем сайте - например, они могут использовать программу для воспроизведения данных голосом и просто слушать, что написано на вашей странице.

Страница HTML, которая не содержит ошибок, в основном будет корректно отображаться в большинстве браузеров, а также будет соответствовать требованиям будущих технологий. Здесь стоит упомянуть поисковые механизмы, действие которых очень важно для целей SEO. Никто не хочет создавать для них препятствий, а чистый и правильный код гораздо легче воспринимается поисковыми ботами.

Это также вопрос профессионализма. Неправильный код HTML очень похож на грамматические ошибки в надписях на сайте. И хотя клиент может и не заметить ошибок в коде - это не изменяет сущности вопроса. Никто не любит грамматические ошибки в дизайне, но оставлять код HTML с ошибками почему-то не считается таким же постыдным деянием.

Общие ошибки

Ниже представлены ошибки, которые выловлены в шаблонах с первой страницы известной галереи CSS шаблонов. Множество сайтов выглядят отлично и даже великолепно, но очень часто качество кода не соответствует качеству дизайна. Хотя большинство таких ошибок может быть исправлено очень быстро и просто.


Самая плохая ошибка - не использовать Doctype ! Отсутствие тега Doctype означает, что браузер будет "догадываться", какой язык использовался для создания документа. Для исправления ошибки нужно указать тип документа вашей страницы .

Не закрыт элемент


Если вы открыли тег где-то в вашем документе HTML, его нужно закрыть в соответствующем месте. Забывчивость в данном вопросе не только приводит к ошибкам при проверке кода, но и может вызвать серьезные проблемы с шаблоном. На рисунке представлена ситуация, когда автор забыл закрыть тег

Опускается символ / в самозакрывающихся элементах


Большинство элементов HTML имеет отдельные закрывающие теги, например: