Кратенькое руководство на тему как сделать в Ruby on Rails форму отправки сообщений на аяксе (ajax) - штуку крайне полезную, пользующуюся сегодня у всех слоев народонаселения самым неподдельным интересом. Одним словом, без долгих раздумий - вперед.
Flash-message формы реализуем, что называется, своими руками, без использования заслуженных unobtrusive_flash и Growlyflash, о которых (в частности) речь в этом топике форума, также можно глянуть для кругозора и эту темку. Чтобы не повторяться, приведу ссылки на статьи блога, озаглавленные jQuery и Bootstrap для Ruby on Rails 6 и Форма обратной связи на Ruby on Rails, и далее сразу переходим собственно к ajax.
Итак, будем считать, форма отправки сообщений, перезагружающая страничку (или перенаправляющая на другую) у нас уже есть, и задача сформулирована следующим образом: научить ее работать посредством ajax. В Ruby on Rails, изначально заточенной под аякс, это крайне несложно; попросту добавьте remote: true к хелперу simple_form (все то же самое, если обходитесь form_with):
<%= simple_form_for @contact, remote: true do |f| %>
Метод способен выглядеть вот так:
def create
@contact = Contact.new(contact_params)
if verify_recaptcha
respond_to do |format|
if @contact.save
FormMailer.with(form: @contact).new_form_email.deliver_later
format.js { flash.now[:success] = 'Thank you for your message.' }
else
format.js { flash.now[:error] = see_errors(@contact) }
end
end
end
end
private
def contact_params
params.require(:contact).permit(:name, :email, :subject, :message)
end
Два замечания. В случае неудачи отправки очень хотелось бы вывести flash-сообщение, описывающее ошибку (или перечень ошибок), приведших к афронту; для этого я написал метод see_errors. Т.е. - проверяем заполнение полей формы не только на стороне клиента ( required: true ), но и на сервере:
def see_errors(x)
if x.errors.any?
view_context.pluralize(x.errors.count, 'error').to_s +
' prohibited this call from being send: ' +
x.errors.full_messages.map { |i| %('#{i}') }.join(',')
end
end
Теперь добавим валидации Active Record в модель. Например:
class Contact < ApplicationRecord
validates :name, presence: true
validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create, message: 'Invalid email' }
validates :subject, length: { minimum: 5 }
validates :message, length: { minimum: 15 }
end
Результат не заставляет себя ждать:
И второе. Если отправка письма ( т.е. if @contact.save ) увенчается успехом - с целью очистки формы зачастую звучит рекомендация реинициализировать объект:
@contact = Contact.new
- не уверен. Я бы лучше добавил reset в файл create.js.erb, который вам предстоит создать в директории, содержащей вьюхи контроллера:
create.js.erb
console.log("This is the create.js.erb file");
$('#template').html("<%= j render 'template' %>");
$("#new_contact")[0].reset();
$('#flash-message').html("<%= j render 'shared/flash' %>").delay(4000).fadeOut(4000).css({display:"block"});
Примечание. Весь код полностью (а не фрагментарно) возможно увидеть в моем гитхабе, репозиторий называется CRUD-Blog:
Демо:
Теперь, что касается render 'shared/flash':
_flash.html.erb
<div class="container">
<% flash.each do |type, msg| %>
<div class="alert <%= bootstrap_class_for_flash(type) %> alert-dismissable fade show">
<%= msg %>
</div>
<% end %>
</div>
, соответственно:
application_helper.rb
module ApplicationHelper
def bootstrap_class_for_flash(flash_type)
case flash_type
when 'success'
'alert-success'
when 'error'
'alert-danger'
when 'warning'
'alert-warning'
when 'notice'
'alert-info'
else
flash_type.to_s
end
end
end
Пожалуй, это все. В том случае, если вы не вознамеритесь добавить последний (на сегодня) штрих: выключить кнопку отправки сообщений до успешного прохождения recaptcha. Что крайне несложно:
1. Меняем в HTML тэг recaptcha следующим образом:
<%= recaptcha_tags :callback => "enableBtn" %>
2. Submit, кнопка отправки:
<%= f.submit :Send, id: 'sbm', disabled: 'disabled' %>
3 и последнее:
<script>
function enableBtn(){
document.getElementById("sbm").disabled = false;
}
</script>
Комментарии в блоге