Статьи

Мини-чат с рельсами

Комментарии - Иконка

Комментарии есть везде. Возможно, вы внедрили какую-то систему комментирования в некоторых ваших проектах (если нет, то вас может заинтересовать моя статья «Вложенные комментарии с Rails» ).

Но что, если мы хотим создать полностью асинхронную систему комментирования, в которой пользователь не испытывает перезагрузки страницы при отправке или получении новых комментариев? Какие инструменты мы могли бы использовать для решения этой задачи? С какими проблемами мы можем столкнуться и как их можно решить?

В этой серии статей, состоящей из двух частей, я покажу вам, как создать полнофункциональный мини-чат на Rails за шесть итераций. Мы обсудим следующие темы:

  • Аутентификация через несколько социальных сетей (OAuth 2, OmniAuth)
  • Асинхронное размещение комментариев
  • Мгновенная загрузка новых комментариев без необходимости перезагрузки страницы (мы обсудим два возможных решения: опрос AJAX и веб-сокеты с Фэй)

Мы также собираемся обсудить некоторые предупреждения, о которых вы должны знать, с опросом AJAX и безопасностью Фэй.

Исходный код доступен на GitHub .

Проверьте рабочую демонстрацию на http://sitepoint-minichat.herokuapp.com/ .

Некоторое Планирование

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

Хорошо, прежде чем начать наше путешествие, давайте запишем требования для нашего приложения для мини-чата:

  • Только прошедшие проверку пользователи могут читать и оставлять комментарии.
  • Пользователи должны иметь возможность проходить аутентификацию через Facebook или Twitter.
  • Каждый комментарий должен содержать имя пользователя, аватар и ссылку на его профиль в социальной сети.
  • Комментарии должны быть опубликованы и получены мгновенно (ну, почти мгновенно), без каких-либо перезагрузок страницы.
  • Пустые и очень длинные комментарии не допускаются.
  • Когда пользователи входят в чат, они должны иметь возможность прочитать некоторые комментарии, которые были опубликованы ранее. Старые комментарии должны быть удалены автоматически.

Отлично, требования сформулированы, и пришло время перейти к первой (и, вероятно, самой большой) итерации — держитесь крепче!

Аутентификация

Начните с создания нового приложения Rails без набора тестов по умолчанию:

$ rails new mini_chat -T 

Прежде чем копаться в коде, остановитесь на минуту и ​​подумайте о системе аутентификации, которую мы собираемся внедрить для этого приложения. Поскольку мы хотим, чтобы наши пользователи могли входить через Facebook и Twitter, будет использоваться протокол OAuth 2 . Вы, наверное, слышали об OAuth2, но если нет — не волнуйтесь — я объясню основы.

Основная идея OAuth2 заключается в том, что пользователь вводит свои учетные данные на самом сайте платформы (в нашем случае это Twitter или Facebook). Таким образом, пользователь никогда не раскрывает свой пароль для нашего приложения; вместо этого веб-сайту предоставляется только некоторая информация об учетной записи пользователя (имя, фамилия, URL профиля, аватар и т. д.) и пара ключей (или один ключ, в зависимости от платформы), которая используется для выполнения вызовов API (для Например, чтобы опубликовать сообщение на Facebook от имени пользователя).

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

Когда начинается этап аутентификации, сторонний веб-сайт пересылает специальный ключ приложения, используемый для идентификации веб-сайта. Также отправляется массив действий, которые ресурс хочет выполнить. Пользователю предлагается диалоговое окно, объясняющее, что этот веб-сайт хочет, чтобы он прошел аутентификацию, и запрашивает разрешение на выполнение списка действий. Если пользователь соглашается, он перенаправляется обратно на сайт с информацией о пользователе, который только что прошел аутентификацию, а также с парой ключей для выполнения вызовов API.

Сначала это может показаться сложным. В действительности мы можем легко реализовать этот сценарий в приложении Rails.

Прежде всего нам нужна модель и таблица для хранения информации об аутентифицирующем пользователе. На самом деле, нам даже не нужны ключи API, потому что мы не собираемся делать какие-либо вызовы API. Для этой демонстрации давайте сохраним следующую информацию в таблице users :

  • provider ( string ) — название социальной сети, которая использовалась для аутентификации. В нашем случае это будет «фейсбук» или «твиттер».
  • name ( string ) — имя пользователя (необязательно с фамилией, но это зависит от того, что пользователь ввел при создании своего профиля).
  • profile_url ( string ) — ссылка на профиль пользователя.
  • avatar_url ( string ) — ссылка на аватар пользователя.
  • uid ( string ) — уникальный идентификатор пользователя в социальной сети. Посмотрим, зачем это нужно чуть позже.

Перейдите и создайте необходимую миграцию:

 $ rails g model User name:string avatar_url:string provider:string profile_url:string uid:string 

Теперь откройте файл миграции и немного change его, добавив следующие строки в конце метода change :

xxx_create_users.rb

 [...] def change [...] add_index :users, :uid add_index :users, :provider add_index :users, [:uid, :provider], unique: true end [...] 

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

Применить миграцию:

 $ rake db:migrate 

В этот момент мы можем перейти к самой аутентификации. К счастью, есть драгоценные камни, которые сделают нашу жизнь намного проще — это omniauth-facebook от Mark Dodwell и omniauth-twitter от Arun Agrawal. О чем этот суффикс «omniauth»?

OmniAuth — это драгоценный камень, созданный Intridea, Inc., предназначенный для стандартизации аутентификации нескольких поставщиков для веб-приложений. OmniAuth позволяет вам использовать столько разных стратегий аутентификации, сколько вам нужно, чтобы ваши пользователи могли проходить аутентификацию через OpenID, Facebook, Twitter, Google и т. Д. Существует несколько стратегий на выбор, но вы можете создать свою собственную . Для этого приложения мы будем использовать две стратегии: Twitter и Facebook, упакованные в эти две жемчужины.

Бросьте эти драгоценные камни в Gemfile

Gemfile

 [...] gem 'omniauth-facebook' gem 'omniauth-twitter' 

и беги

 $ bundle install 

Теперь мы должны зарегистрировать наш сайт как приложение в Facebook и Twitter. Посетите https://developers.facebook.com/apps и создайте новое приложение здесь. Дайте ему имя в разделе «Настройки» (я назвал это «SitePoint Mini-Chat Demo»). Не забывайте, что это имя будет видно для аутентифицирующего пользователя! Далее нажмите «Добавить платформу» и выберите «Веб-сайт». Заполните «URL сайта» (в моем случае я ввел «http://sitepoint-minichat.herokuapp.com/») и «Домены приложений» (я ввел «sitepoint-minichat.herokuapp.com»). Имейте в виду, этот домен должен быть получен из URL, иначе ваши настройки не будут сохранены. Также укажите «Контактный E-mail» и нажмите «Сохранить». Перейдите к «Status & Review» и переключите «Хотите ли вы сделать это приложение и все его живые функции доступными для широкой публики?» Переключитесь на «Yes».

Для настоящего приложения потратьте некоторое время на настройку параметров другого приложения (например, изображения, описания, слогана и т. Д.). Мы перейдем к разделу «Панель инструментов». Здесь обратите внимание на поля «Идентификатор приложения» и «Секрет приложения» (последнее маскируется). Нажмите «Показать», чтобы открыть Секрет, и введите свой пароль — это ключи, которые нам понадобятся для настройки аутентификации.

Создайте новый файл с именем omniauth.rb в config / initializer и вставьте следующий код:

конфиг / Инициализаторы / omniauth.rb

 Rails.application.config.middleware.use OmniAuth::Builder do provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'], scope: 'public_profile', display: 'page', image_size: 'square' end 

Для хранения пары ключей я использую переменные среды Heroku . Как вы, наверное, догадались, FACEBOOK_KEY — это «Идентификатор приложения», а FACEBOOK_SECRET — «Секрет приложения».

Область scope — это список разрешений, которые запрашивает наше приложение. Поскольку мы не будем получать доступ к каким-либо функциям API Facebook, единственным запрашиваемым разрешением является public_profile что означает «получить основные данные пользователя». Узнайте больше о разрешениях Facebook здесь .

display — это еще один параметр, отправляемый Facebook при аутентификации, который управляет тем, как будет выглядеть страница аутентификации. Например, если вы открываете страницу аутентификации в небольшом всплывающем окне, вы можете указать popup в качестве display значения. Узнайте больше здесь .

Последний параметр — это image_size , который контролирует размер аватара пользователя, который мы хотим получить. square означает «изображение 50×50 пикселей».

Теперь нам нужно сделать то же самое для Twitter. Перейдите на https://apps.twitter.com/ и
создать новое приложение. Дайте ему имя, описание и URL. Кроме того, введите URL-адрес обратного вызова в следующем
Формат: « apps’s_URL / auth / twitter / callback». Этот формат определяется OmniAuth и является ресурсом, на который пользователь будет перенаправлен после успешной аутентификации. Мы позаботимся об этом через мгновение.

Далее примите условия и создайте приложение. Возможно, вы захотите потратить некоторое время, настроив другие параметры своего приложения, такие как название организации, значок и т. Д. Кроме того, обратите внимание, что в области сведений вы можете изменить уровень доступа приложения. Мы будем сохранять настройку «Только для чтения» по умолчанию.

Open API Keys — здесь находятся ключ API и секрет API. Вернитесь к файлу omniauth.rb и добавьте еще код:

конфиг / Инициализаторы / omniauth.rb

 Rails.application.config.middleware.use OmniAuth::Builder do provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'], image_size: 'normal' [...] 

Вставьте свои ключи непосредственно в этот файл или используйте какой-либо другой способ для их хранения (что рекомендуется — они не должны быть видны всем). Опция image_size предоставляет аватар пользователя в виде изображения размером 48×48 пикселей. Полный список доступных опций смотрите в документации .

Хорошо, мы закончили с, вероятно, самой утомительной задачей этой демонстрации и готовы продолжить. Помните URL обратного вызова? Нам нужно создать соответствующий маршрут сейчас:

конфиг / routes.rb

 [...] get '/auth/:provider/callback', to: 'sessions#create' get '/auth/failure', to: 'sessions#auth_fail' get '/sign_out', to: 'sessions#destroy', as: :sign_out [...] 

Я также создал sign_out и маршруты с sign_out аутентификации.

На контроллере:

sessions_controller.rb

 class SessionsController < ApplicationController def create user = User.from_omniauth(request.env['omniauth.auth']) cookies[:user_id] = user.id flash[:success] = "Hello, #{user.name}!" redirect_to root_url end def destroy cookies.delete(:user_id) flash[:success] = "See you!" redirect_to root_url end def auth_fail render text: "You've tried to authenticate via #{params[:strategy]}, but the following error occurred: #{params[:message]}", status: 500 end end 

В действии create вызовите создаваемый метод from_omniauth и передайте request.env['omniauth.auth'] в качестве аргумента. Хеш request.env['omniauth.auth'] содержит всю информацию об аутентифицированном пользователе (он называется «хеш аутентификации»).

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

Действие destroy еще проще. Просто удалите cookie user_id , установите сообщение до свидания и перенаправьте на главную страницу.

Если вы хотите взглянуть на хеш аутентификации, вы можете заменить код метода create на следующую строку:

 render text: request.env['omniauth.auth'].to_yaml 

затем перейдите к « your_app’s_url / auth / twitter /» (или «auth / facebook») и просмотрите результаты.

Нам нужен метод User.from_omniauth . В этом методе пользователь должен быть создан или найден (по его уникальному идентификатору и имени в социальной сети) и обновлен:

модели / user.rb

 class User < ActiveRecord::Base class << self def from_omniauth(auth) provider = auth.provider uid = auth.uid info = auth.info.symbolize_keys! user = User.find_or_initialize_by(uid: uid, provider: provider) user.name = info.name user.avatar_url = info.image user.profile_url = info.urls.send(provider.capitalize.to_sym) user.save! user end end end 

Здесь я использую symbolize_keys! метод для вызова методов, таких как info.name . Как видите, мы получаем всю необходимую информацию о пользователе, затем сохраняем запись и возвращаем user в результате.

Вы можете заметить строку info.urls.send(provider.capitalize.to_sym) . Поскольку мы работаем с несколькими провайдерами, URL-адреса обычно возвращаются следующим образом:

 :urls => { :Twitter => "https://twitter.com/johnqpublic" } 

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

На данный момент мы на 95% завершили аутентификацию. Если вам когда-нибудь понадобится добавить дополнительные параметры аутентификации, такие как Open ID или Google, это можно сделать легко. Просто измените файл initializers / omniauth.rb , добавив другого провайдера, и протестируйте хэш аутентификации (некоторые социальные сети могут представлять хэш, немного отличающийся от тех, которые мы только что видели).

Последний шаг здесь — предоставить нашим пользователям ссылки для аутентификации. Прежде чем сделать это, нам нужен корневой маршрут и соответствующее представление, поэтому давайте сделаем это на следующей итерации.

Комментарии

В этой итерации нам нужно переключиться на комментарии — в конце концов, мы создаем приложение для обмена сообщениями. Давайте назовем нашу модель Comment и она будет содержать следующие поля (кроме id по умолчанию, created_at , updated_at ):

  • body ( text ) — фактическое сообщение.
  • user_id ( integer ) — внешний ключ, указывающий на пользователя, который разместил это сообщение.

Как видите, это действительно простая модель. Создайте и примените миграцию:

 $ rails g model Comment body:text user:references $ rake db:migrate 

Не забудьте открыть user.rb и добавить эту строку:

модели / user.rb

 [...] has_many :comments, dependent: :delete_all [...] 

Отлично, на данный момент мы готовы добавить несколько маршрутов:

конфиг / routes.rb

 [...] resources :comments, only: [:new, :create] root to: 'comments#new' [...] 

Нам нужно только new и create действия для этой демонстрации. Мы не собираемся создавать бэкэнд для управления комментариями, но вы можете добавить эту функцию самостоятельно.

Соответствующий контроллер (методы будут заполнены позже):

comments_controller.rb

 class CommentsController < ApplicationController def new @comment = Comment.new end def create end end 

Прежде чем создавать представление, подключите Bootstrap, чтобы помочь нам с дизайном:

Gemfile

 [...] gem 'bootstrap-sass' [...] 

application.css.scss

 @import 'bootstrap'; @import 'bootstrap/theme'; 

Также измените ваш макет, чтобы использовать в своих интересах стили Bootstrap:

макеты / application.html.erb

 [...] <body> <div class="navbar navbar-default navbar-static-top"> <div class="container"> <div class="navbar-header"> <%= link_to 'Mini-chat', root_path, class: 'navbar-brand' %> </div> </div> </div> <div class="container"> <% flash.each do |key, value| %> <div class="alert alert-<%= key %>"> <%= value %> </div> <% end %> <%= yield %> </div> </body> [...] 

Хорошо, теперь мы можем перейти к единственному виду:

комментарии / new.html.erb

 <div class="jumbotron"> <h1>Welcome to our mini-chat!</h1> <p class="lead">Please sign in via one of the social networks to start chatting</p> <%= link_to '', '/auth/twitter', class: 'social twitter' %> <%= link_to '', '/auth/facebook', class: 'social facebook' %> </div> 

Это место, где мы предоставляем пользователям ссылки для аутентификации. Часть аутентификации определяется OmniAuth, а имя этого провайдера определяется (в нашем случае, facebook или twitter ). Давайте также немного стилизуем эти ссылки. Вероятно, самый простой способ добиться этого — использовать иконки социальных сетей, которые распознаются практически любым пользователем Интернета. Чтобы загрузить официальные значки, посетите следующие ресурсы: https://www.facebookbrand.com/ и https://about.twitter.com/press/brand-assets . Я уже создал изображение спрайта (с помощью http://csssprites.com/ ), которое вы можете использовать.

Теперь примените немного стиля:

application.css.scss

 [...] .social { background: image-url('logos.png') no-repeat transparent; display: inline-block; &.twitter { width: 50px; height: 42px; background-position: 0 -52px; } &.facebook, &.facebook:active { width: 50px; height: 50px; background-position: 0 0; } } 

Обратите внимание, что здесь я использую image-url потому что в противном случае мое фоновое изображение не будет отображаться в Heroku.

Прежде чем перейти к форме комментирования, нам нужно проверить, прошел ли пользователь аутентификацию. Традиционно этот метод называется current_user :

application_controller.rb

 def current_user @current_user ||= User.find_by(id: cookies[:user_id]) if cookies[:user_id] end helper_method :current_user 

С помощью этого метода мы можем предоставить аутентифицированному пользователю ссылку «Выйти»:

макеты / application.html.erb

 [...] <div class="navbar navbar-default navbar-static-top"> <div class="container"> <div class="navbar-header"> <%= link_to 'Mini-chat', root_path, class: 'navbar-brand' %> </div> <% if current_user %> <ul class="nav navbar-nav navbar-right"> <li><%= image_tag current_user.avatar_url %></li> <li><%= link_to 'Sign out', sign_out_path %></li> </ul> <% end %> </div> </div> [...] 

Возвращаясь к виду:

комментарии / new.html.erb

 <% if current_user %> <div class="page-header"> <h1>Join the discussion!</h1> </div> <%= render 'form' %> <% else %> <%= render 'welcome' %> <% end %> 

Я извлек приветственное сообщение вместе со ссылками на аутентификацию в отдельный раздел:

комментарии / _welcome.html.erb

 <div class="jumbotron"> <h1>Welcome to our mini-chat!</h1> <p class="lead">Please sign in via one of the social networks to start chatting</p> <%= link_to '', '/auth/twitter', class: 'btn social twitter' %> <%= link_to '', '/auth/facebook', class: 'btn social facebook' %> </div> 

Теперь создайте частичную форму :

комментарии / _form.html.erb

 <div class="well"> <%= form_for @comment do |f| %> <div class="form-group"> <%= f.label :body, 'Enter your comment:' %> <%= f.text_area :body, rows: 3, class: 'form-control', required: true, maxlength: 2000 %> <small class="label label-warning">Cannot be blank or contain more than 2000 symbols.</small> </div> <%= f.submit 'Post', class: 'btn btn-primary btn-lg' %> <% end %> </div> 

Здесь ничего необычного — одна текстовая область для ввода сообщения и кнопка «Опубликовать». Нам также нужна проверка, чтобы пользователи не могли отправлять пустые или очень длинные сообщения:

модели / comment.rb

 [...] validates :body, presence: true, length: {maximum: 2000} [...] 

Позже вы также можете добавить некоторую проверку на стороне клиента (например, с помощью плагина jQuery Validate ).

Последнее, что нужно сделать, это create действие create :

comments_controller.rb

 [...] def create if current_user @comment = current_user.comments.build(comment_params) if @comment.save flash[:success] = 'Your comment was successfully posted!' else flash[:error] = 'Your comment cannot be saved.' end end redirect_to root_url end private def comment_params params.require(:comment).permit(:body) end [...] 

Наши пользователи теперь могут оставлять свои комментарии. Однако они их не увидят. Давайте это исправим!

comments_controller.rb

 [...] def new @comment = Comment.new @comments = Comment.order('created_at DESC') end [...] 

комментарии / new.html.erb

 <% if current_user %> <div class="page-header"> <h1>Join the discussion!</h1> </div> <%= render 'form' %> <div class="panel panel-default" id="comments"> <div class="panel-body"> <ul class="media-list"> <%= render @comments %> </ul> </div> </div> <% else %> <%= render 'welcome' %> <% end %> 

Я использую еще один @comments который будет отображаться для каждого комментария в массиве @comments :

комментарии / _comment.html.erb

 <li class="media comment"> <%= link_to image_tag(comment.user.avatar_url, alt: comment.user.name, class: "media-object"), comment.user.profile_url, target: '_blank', class: 'pull-left' %> <div class="media-body"> <h4 class="media-heading"><%= link_to comment.user.name, comment.user.profile_url, target: '_blank' %> says <small class="text-muted">[at <%= comment.created_at.strftime('%-d %B %Y, %H:%M:%S') %>]</small></h4> <p><%= comment.body %></p> </div> </li> 

И наконец, немного стиля:

application.css.scss

 [...] #comments { max-height: 500px; overflow: auto; } 

На этом этапе запустите сервер, авторизуйтесь через одну из социальных сетей и попытайтесь опубликовать некоторые комментарии. Мы готовы перейти к следующей итерации!

Удаление лишних комментариев

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

Я собираюсь использовать дополнение Heroku Scheduler здесь, но вы можете использовать другое решение, например Rufus Scheduler .

Это дополнение можно установить с помощью следующей команды (обратите внимание, что ваше приложение должно быть уже создано в Heroku):

 $ heroku addons:add scheduler:standard 

Далее создайте актуальную задачу:

Lib / задачи / scheduler.rake

 desc "This task is called by the Heroku scheduler add-on" task remove_excessive_comments: :environment do puts "Removing excessive comments now..." Comment.remove_excessive! end 

и remove_excessive! метод:

модели / comment.rb

 [...] class << self def remove_excessive! if all.count > 100 order('created_at ASC').limit(all.count - 50).destroy_all end end end [...] 

Числа здесь произвольные, поэтому настройте их по своему усмотрению. Общая идея здесь, если есть много комментариев, удалите все, кроме последних 50.

Вы можете проверить эту задачу, запустив

 $ heroku run rake remove_excessive_comments 

Когда вы будете готовы запустить

 $ heroku addons:open scheduler 

и создайте новую задачу здесь (введите rake remove_excessive_comments в поле «Task») с необходимой частотой.

Вы также можете использовать бесконечную прокрутку, чтобы постепенно загружать старые комментарии по мере их прокрутки вниз — ознакомьтесь с моей статьей «Бесконечная прокрутка в Rails: основы», чтобы узнать больше.

Добавляем немного AJAX

Это будет последняя итерация на сегодня. Давайте добавим немного AJAX, чтобы сделать процесс публикации комментариев асинхронным. Таким образом, страница не будет перезагружаться каждый раз, когда пользователь публикует свой комментарий.

Если вы используете Turbolinks, я рекомендую добавить гем jquery-turbolinks, чтобы вернуть события загрузки страницы по умолчанию (поскольку изначально Turbolinks имеет свои собственные события ).

Gemfile

 [...] gem 'jquery-turbolinks' [...] 

application.js

 [...] //= require jquery.turbolinks //= require turbolinks 

Чтобы снабдить нашу форму AJAX, требуется только одна модификация:

комментарии / _form.html.erb

 <%= form_for @comment, remote: true do |f| %> 

Метод create контроллера также должен быть модифицирован для обработки AJAX-запросов:

comments_controller.rb

 [...] def create respond_to do |format| if current_user @comment = current_user.comments.build(comment_params) if @comment.save flash.now[:success] = 'Your comment was successfully posted!' else flash.now[:error] = 'Your comment cannot be saved.' end format.html {redirect_to root_url} format.js else format.html {redirect_to root_url} format.js {render nothing: true} end end end [...] 

Здесь используется метод respond_to для ответа в правильном формате: либо HTML (если пользователь отключил JavaScript в своем браузере), либо JS. Также необходимо создать новый вид:

комментарии / create.js.erb

 <% if @comment.new_record? %> alert('Your comment cannot be saved.'); <% else %> $('#comments').find('.media-list').prepend('<%= j render @comment %>'); $('#comment_body').val(''); <% end %> 

Мы используем if @comment.new_record? условие, чтобы проверить, был ли комментарий сохранен. Если да — добавьте новый комментарий к списку комментариев ( _comment.html.erb частично) и очистите текстовую область. Вы можете немного расширить эту функциональность, предупреждая (или отображая каким-либо другим способом) список ошибок, которые были обнаружены, если комментарий не был сохранен.

Попробуйте и опробуйте новую форму на AJAX. Действительно, это работает хорошо, но многое еще предстоит сделать. Основная проблема заключается в том, что пользователю все еще нужно перезагрузить страницу, чтобы увидеть, что другие опубликовали, однако в реальном чате она увидит новые комментарии, как только они будут добавлены. Так что это наша задача на следующий раз!

Вывод

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

В следующей части мы поговорим о двух возможных способах отображения новых комментариев для пользователя:
AJAX опросы и веб-розетки. Мы обсудим, какое решение лучше подходит для наших нужд, а также определим некоторые ошибки.