Vinaora Nivo Slider 3.xVinaora Nivo Slider 3.xVinaora Nivo Slider 3.xVinaora Nivo Slider 3.xVinaora Nivo Slider 3.xVinaora Nivo Slider 3.xVinaora Nivo Slider 3.xVinaora Nivo Slider 3.x
Четверг, 07 апреля 2022 02:09

Из цикла «Сделай сам». Продвинутый слайдер изображений на Rails и Bootstrap — за час

Оцените материал
(0 голосов)

Краткий туториал проведет вас, шаг за шагом, через все этапы создания элегантного слайдера на основе Ruby on Rails 6 и Bootstrap 5; мне хотелось,чтобы несложный этот rails-app обладал, тем не менее, некоторым рядом опций, управление которыми реализовано посредством удобной панели управления ActiveAdmin.

Данная дока не является переводом или адаптацией чьих-то иных усилий: как авторство, так и любые щелчки по носу по праву принадлежат лишь автору в награду за его бессонную ночь (но не за "ночную сборку", не подумайте), ушедшую на написание этой статьи и (в значительно меньшей степени) создание собственно rails-app. Описанная далее последовательность команд выверена вполне добросовестно, придерживайтесь ее: приложение тщательно оттестировано.

 

Увидеть на гитхабе.

 

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

 

$ git clone https://github.com/cmirnow/slider-on-rails.git
$ cd slider-on-rails
$ bundle install
$ yarn install --check-files
$ rails s

 

Да, и сразу о функционале. Слайдер имеет два способа анимации смены изображений, возможность регулирования временного интервала показа слайда, также изменение стиля отображения "светло/темно" в границах от 0.0 до 0.9, плюс возможность добавить для каждого изображения (или не для каждого) текстовой слоган, отображаемый в левом верхнем углу, цвет текста слогана также доступен для выбора. Добавляем следующим образом: один слоган - одна линия - один слайд, пустая строчка означает отсутствие текста для соответствующего изображения:

 

Из цикла «Сделай сам». Продвинутый слайдер изображений на Rails и Bootstrap — за час.
Из цикла «Сделай сам». Продвинутый слайдер изображений на Rails и Bootstrap — за час.


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

 

 

Слайдер изображений работает во многом благодаря фреймворку ActiveStorage: в режиме разработки (т.е., иными словами, у вас на ПК) используется локальное хранилище, но после деплоя на Heroku приложение начинает работать как продакшн и, соответственно, под хранилище слайдов используется Amazon S3 либо любое иное совместимое. Впрочем, все эти дефолтлные настройки легко меняются в конфигах, при необходимости.

 

Из цикла «Сделай сам». Продвинутый слайдер изображений на Rails и Bootstrap — за час.
Из цикла «Сделай сам». Продвинутый слайдер изображений на Rails и Bootstrap — за час.

 

ОК. Единственное, что пропущу сейчас, ограничившись скороговоркой - это процедуру установки на ваш рабочий ПК необходимого для работы программного обеспечения. С этим - самостоятельно, доков в Сети хоть отбавляй, было бы желание и вообще не проблема. А ПО, установленное у меня на рабочем компе, таково:

 

$ ruby --version
ruby 2.7.4p191 (2021-07-07 revision a21a3b7d23) [x86_64-linux]
$ rails --version
Rails 7.0.2.3
$ node --version
v14.18.3
$ yarn --version
1.22.18
$ psql --version
psql (PostgreSQL) 12.10

 

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

 

$ mkdir slider_onrails && cd slider_onrails
$ echo "source 'https://rubygems.org'" > Gemfile
$ echo "gem 'rails', '6.1.5'" >> Gemfile
$ bundle install

 

Так, что касается PostgreSQL: необходим только лишь в том случае, если в качестве финала данного мини-семинара вы планируете залить слайдер на Heroku, дабы дать возможность коллегам и работодателям полюбоваться в вебе вашим новым сайтом. "Запушенное" на Heroku приложение работает в режиме production, загружая, как уже было сказано выше, картинки слайдера автоматом на Amazon S3, что очень удобно и вполне себе актуально; так работает, например, новостной агрегатор Медуза (признанный у нас иностранным, блаблабла и все такое прочее, что просится на язык, агентом), это те ж самые рельсы, кто не в курсе; правда, на Медузе есть еще и кэширующий сервер, но не суть. Если подобных планов у вас нет, можете смело убирать -d postgresql при вызове следующей команды (use sqlite3 as the database for Active Record): 

 

$ bundle exec rails new . --force -d postgresql
$ bin/rails db:create

 

Из цикла «Сделай сам». Продвинутый слайдер изображений на Rails и Bootstrap — за час.
Из цикла «Сделай сам». Продвинутый слайдер изображений на Rails и Bootstrap — за час.

 

Здесь я опять сделаю паузу, перебив сам себя и сходу забежав вперед. Учитывая происходящие крайне невеселые события, и в связи с ними невозможность для многих указать номер Visa / MasterCard при регистрации в облаке Амазона - расскажу о нем очень кратко: для Амазона придется (это можно сделать в самом конце работы) добавить в Gemfile gem 'aws-sdk-s3' и сделать еще раз bundle install, затем добавить в консоль Heroku (Reveal Config Vars) четыре пары ключ/значение, полученные в консоли Amazon S3:

 

AWS_ACCESS_KEY_ID '*********************'
AWS_SECRET_ACCESS_KEY '****************************'
REGION '****************************'
BUCKET '****************************'

 

, раскомментировав и слегка отредактировав:

 

# config/storage.yml
amazon:
   service: S3
   access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
   secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
   region: <%= ENV['REGION'] %>
   bucket: <%= ENV['BUCKET'] %>

 

и заменив local на amazon:

 

# config/environments/production.rb
config.active_storage.service = :amazon

 

Но ничего этого (конец ремарки) не нужно, если для начала мы попросту запустим слайдер на локальной машине. Итак, после успеха реализации rails new и db:create, продолжаем:

 

$ yarn add bootstrap@next @popperjs/core

 

(Или же попросту bootstrap, без @next. В приложении использован Bootstrap v.5.1.3, на момент публикации это по умолчанию).

Откроем application.html.erb и добавим одну строчку:

 

# app/views/layouts/application.html.erb
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

 

Создаем новый каталог и новый файл:

 

$ mkdir app/javascript/stylesheets && touch app/javascript/stylesheets/application.scss

 

, который приводим к следующему:

 

@import "bootstrap";

/* Carousel dark overlay */
.carousel-item:after {
    content: "";
    display: block;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}

/* Slider caption style */
.carousel-caption {
    left: 2%;
    top: 5% !important;
    transform: translateY(-50%);
    text-align: left;
    bottom: initial;
}

 

И теперь отредактируем application.js:

 

import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"
import * as bootstrap from 'bootstrap'
import "../stylesheets/application"

Rails.start()
Turbolinks.start()
ActiveStorage.start()

 

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

 

$ rails g model Slider name:string published_at:datetime interval:integer dark:float fade:boolean captions:text color:string
$ rails g controller Slider index

 

Теперь добавим в Gemfile:

 

gem 'image_processing', '~> 1.2'
gem 'activeadmin'
gem 'devise'

 

Далее:

 

$ bundle install
$ rails g active_admin:install
$ rails active_storage:install
$ rails db:migrate
$ rails db:seed
$ rails g active_admin:resource Slider

 

Включаем в маршрутах:

 

# config/routes.rb
root "slider#index"

 

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

 

# config/application.rb
config.active_storage.replace_on_assign_to_many = false

 

Нам осталось лишь внести корректуру в эти файлы:

 

# app/admin/sliders.rb
ActiveAdmin.register Slider do
  permit_params :published_at, :name, :captions, :color, :interval, :dark, :fade, images: []
  remove_filter :images_attachments, :images_blobs, :captions, :color, :interval, :dark, :fade

  scope :all
  scope :published
  scope :unpublished

  exclude_columns = [:captions]
  index do
    selectable_column
    Slider.attribute_names.each do |clmn|
      column clmn unless exclude_columns.include? clmn.to_sym
    end
    actions
  end

  action_item :publish, only: :show do
    link_to 'Publish', publish_admin_slider_path(slider), method: :put unless slider.published_at?
  end

  action_item :unpublish, only: :show do
    link_to 'Unpublish', unpublish_admin_slider_path(slider), method: :put if slider.published_at?
  end

  action_item :delete_images, only: :show do
    link_to 'Delete Images', delete_images_admin_slider_path(slider), method: :delete if slider.images.attached?
  end

  member_action :publish, method: :put do
    slider = Slider.find(params[:id])
    slider.update(published_at: Time.zone.now)
    redirect_to admin_slider_path(slider)
  end

  member_action :unpublish, method: :put do
    slider = Slider.find(params[:id])
    slider.update(published_at: nil)
    redirect_to admin_slider_path(slider)
  end

  member_action :delete_images, method: :delete do
    slider = Slider.find(params[:id])
    # asset = ActiveStorage::Attachment.find_by(params[:attachment_id])
    slider.images.purge_later
    redirect_to admin_slider_path(slider)
  end

  member_action :delete_image, method: :delete do
    slider = Slider.find_by(params[:name])
    slider.images[params[:id].to_i].purge_later
    redirect_to admin_slider_path(slider)
  end

  form do |f|
    f.inputs 'Slider' do
      f.input :fade, as: :boolean, label: 'carousel-fade'
      f.input :name
      f.input :captions, label: 'Captions. One image - one slogan - one line. The string is separated by "\r\n"'
      f.input :color, label: 'Captions color'
      f.input :interval, input_html: { value: f.object.interval || 5000 }
      f.input :dark, input_html: { value: f.object.dark || 0.2 }
      f.input :images, as: :file, input_html: { multiple: true }
    end
    f.actions
  end
  show do |t|
    attributes_table do
      if t.images.attached?
        t.images.each_with_index do |img, index|
          span do
            link_to delete_image_admin_slider_path(index), method: :delete do
              image_tag img.variant(resize_to_limit: [100, 100])
            end
          end
        end
      end
      row :name
      row :created_at
      row :updated_at
      row :published_at
      row :fade
    end
    para 'Click the preview to delete the image.'
  end
end

 

# app/controllers/slider_controller.rb
class SliderController < ApplicationController
  def index
    @slider = Slider.published.take
  end
end

 

# app/models/slider.rb
class Slider < ApplicationRecord
  has_many_attached :images, dependent: :purge_later
  scope :published, -> { where.not(published_at: nil) }
  scope :unpublished, -> { where(published_at: nil) }
end

 

# app/helpers/slider_helper.rb
module SliderHelper
  def slider_present?
    @slider&.images&.attached?
  end

  def slider_dark
    @slider.dark
  end

  def slider_interval
    @slider&.interval || 5000
  end

  def carousel_fade?
    'carousel-fade' if @slider.fade == true
  end

  def captions
    @slider&.captions&.split("\r\n")
  end

  def caption_color
    @slider.color
  end
end

 

# app/views/slider/index.html.erb
<div class="container pt-5">
<% if slider_present? %>
<style>
.carousel-item:after {
    background: rgba(0, 0, 0, <%= slider_dark %>);
}
.carousel-caption h3 {
    color: <%= caption_color %>;
}
</style>
	<div id="SliderOnRails" class="carousel slide <%= carousel_fade? %>" data-bs-ride="carousel" data-bs-interval="<%= slider_interval %>">
		<div class="carousel-inner">
			<% @slider.images.each_with_index do |img, index| %>
				<div class="carousel-item<%= ' active' if index == 0 %>">
					<%= image_tag(img, class:"d-block w-100") %>
					<div class="carousel-caption d-none d-md-block">
						<H3><%= captions[index] %></H3>
					</div>
				</div>
			<% end %>
		</div>
		<button class="carousel-control-prev" type="button" data-bs-target="#SliderOnRails" data-bs-slide="prev"> <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="visually-hidden">Previous</span> </button>
		<button class="carousel-control-next" type="button" data-bs-target="#SliderOnRails" data-bs-slide="next"> <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="visually-hidden">Next</span> </button>
	</div>
<% else %>
	<div class="alert alert-warning" role="alert">
		No slides to display.
	</div>
<% end %>
</div>

 

Пожалуй это все. Готово:

 

$ rails webpacker:compile
$ rails s

 

Как видите, вьюха содержит у меня пару стилей, формируемых динамически, что для Rails несколько "не по фэншую"; но в контексте демонстрационного приложения, пожалуй, подобное приемлемо. Дело в том, что компилируемые Rails Asset Pipeline файлы используются в качестве статических ресурсов, в большинстве случаев компиляция происходит либо при обновлении исходников (в режиме разработке), или во время развертывания (production mode).

 

Открываем в браузере:

 

http://localhost:3000/admin

 

и логинимся:

 

User: Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.
Password: password

 

Все работает, не правда ли?


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

Редактируем db/seeds.rb, убирая в самом конце if Rails.env.development? : напоминаю в очередной раз, приложение работает на Heroku в режиме продакшн, и без данной редакции вы не сможете установить дефолтные значения входа в панель управления ActiveAdmin (об этом далее).

 

Если нужно, чтобы работала функция восстановления пароля - отредактируйте production.rb так, как описано в самом конце этого руководства. Кроме того, помимо уже названных выше Config Vars, в консоль Heroku придется добавить еще три. Будьте внимательны.

 

Вам понадобятся git и скрипты Heroku CLI, подробнее здесь (или много еще где). Далее:

 

git add .
git commit -m "initial commit"
heroku create
git push heroku main
heroku run rake db:migrate
heroku run rake db:seed

 

Быстро логинимся и меняем в панели управления данные для входа, в том случае, разумеется, если не сделали этого сразу, редактируя seeds.rb (в этом случае можно не спешить, но все равно поменяйте пароль). В случае любых проблем открываем и внимательно рассматриваем содержание консоли:

 

$ heroku run rails console

 

Хотя, если все сделаете правильно, проблем быть не должно, проверял. В любом случае, удачи. Пишите, если что.

Последнее изменение Суббота, 09 апреля 2022 06:15

Оставить комментарий

Добавьте ваш комментарий

В блоге

Комментарии в блоге

Заказать сайт

Веб-разработка. Заказать сайт

Вы можете заказать сайт-визитку, блог, корпоративный сайт, интернет-магазин или коммерческий web-портал.