Ruby on Rails замечательно подходит для создания мощного и гибкого бэкенда. Однако из-за популярности и гибкости JavaScript, Ruby используется для фронтэнда не так часто. Тем не менее я считаю, что, используя только HTML, Ruby и CSS, разработчики смогут создавать более качественные сайты. Экспериментируя с созданием более динамических страниц без JavaScript, мы можем научиться грамотно использовать cookie-файлы и снизить зависимость от скриптов, влияющих на производительность.

Хороший способ попрактиковаться в использовании cookie-файлов с Rails — это создать для веб-сайта простую функцию поиска и сортировки. Давайте рассмотрим компоненты, которые делают возможными оба эти действия одновременно.

Код

Для этого примера используем очень простое приложение для фэнтези-футбола, полный код которого можно найти здесь

ruby
  def initialize_search
    @teams = Team.alphabetical
    session[:search_name] ||= params[:search_name]
    session[:filter] = params[:filter]
    params[:filter_option] = nil if params[:filter_option] == ""
    session[:filter_option] = params[:filter_option]
  end
  
  def handle_search_name
    if session[:search_name]
      @players = Player.where("name LIKE ?", "%#{session[:search_name].titleize}%")
      @teams = @teams.where(code: @players.pluck(:team))
    else
      @players = Player.all
    end
  end

  def handle_filters
    if session[:filter_option] && session[:filter] == "position"
      @players = @players.where(position: session[:filter_option])
      @teams = @teams.where(code: @players.pluck(:team))
    elsif session[:filter_option] && session[:filter] == "team"
      @teams = @teams.where(code: session[:filter_option])
    end
  end

Эти методы обрабатывают запросы имен игроков из базы данных. 

Первый метод, handle_search_name, берет cookie-файл, содержащий данные поиска, введенные пользователем, и использует их для выделения игроков, чьи имена соответствуют поисковому запросу, используя метод activerecord, где @players = Player.where("name LIKE ?", "%#{session[:search_name].titleize}%").

Метод handle_filters берет доступный в данный момент список игроков и отфильтровывает по подходящему параметру @players = @players.where(position: session[:filter_option]).

Оба эти метода основаны на сессиях. Сессия — это фактически набор cookie-файлов. Эти cookie-файлы передаются через параметры, отправленные обратно на сервер как часть запроса get из формы. Давайте посмотрим, как они отправляются. 

 ruby
  def initialize_search
    @teams = Team.alphabetical
    session[:search_name] ||= params[:search_name]
    session[:filter] = params[:filter]
    params[:filter_option] = nil if params[:filter_option] == ""
    session[:filter_option] = params[:filter_option]
  end
  
  def handle_search_name
    if session[:search_name]
      @players = Player.where("name LIKE ?", "%#{session[:search_name].titleize}%")
      @teams = @teams.where(code: @players.pluck(:team))
    else
      @players = Player.all
    end
  end

  def handle_filters
    if session[:filter_option] && session[:filter] == "position"
      @players = @players.where(position: session[:filter_option])
      @teams = @teams.where(code: @players.pluck(:team))
    elsif session[:filter_option] && session[:filter] == "team"
      @teams = @teams.where(code: session[:filter_option])
    end
  end 

Форма выше отправляет запрос get обратно той же странице, но передает пользовательский поисковый запрос как параметр search_name.

Затем в контроллере Rails используем:

session[:search_name] = params[:search_name]

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

Почему сессии?

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

Сессия в Rails — это зашифрованный набор cookie-файлов. Если мы не хотим, чтобы пользователи вручную редактировали отдельные cookie-файлы, мы используем сессию. В данном конкретном случае мы хотим контролировать, когда конкретные cookie-файлы сохраняются и удаляются. Для этого мы поместим все cookie-файлы в сессию, а не будем хранить отдельными файлами. 

Поиск и фильтрация одновременно 

Теперь, когда пользователь дал нам поисковый запрос, мы можем сузить область поиска, используя фильтр. В нашем HTML есть форма для каждого параметра фильтра, давайте посмотрим на один из них:

html
  <select name="filter_option" onchange="this.form.submit()">
    <option value="">Pick a Team</option>
    <% @teams.each do |team| %>
      <option value="<%= team.code %>"><%= team.name %></option>
    <% end %>
  </select>

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

Отображение результатов

Самый приятный момент — отображение результатов на странице. 

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

ruby
  def index
    initialize_search
    handle_search_name
    handle_filters
  end

Затем в HTML создаем элементы, которые будут возвращены в отсортированный набор данных. 

html
  <% @teams.each do |team| %>
  <h2>
    <%= team.name %>
  </h2>
  <ul>
    <% @players.where(team: team.code).each do |player| %>
      <li>
        <%= link_to "#{player.name} | #{player.position}", player %>
      </li>
    <% end %>
  </ul>
<% end %>

Вуаля! Конечный результат должен выглядеть примерно так:

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

Читайте также:


Перевод статьи Sukrit Walia: Making a Search and Filter Function in Ruby on Rails

Предыдущая статьяVue.js 3: программирование, ориентированное на будущее
Следующая статьяАвтоматизация обновления Angular