[Ruby on Rails] Joomla on Rails, или особенности национального веб-программирования
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Рунет производит на меня (и не только в контексте веб-программирования) крайне противоречивое впечатление. Возможно, так и должно быть, типа "Нью-Йорк - город контрастов"? - по крайней мере, та полупрофессиональная и пестрая интернет-тусовка, к которой обычно приходят новички, мечтающие выучиться на веб-программиста. Говоря словами героя пьесы Евгения Шварца - "очень трудно будет все это распутать, разобрать и привести в порядок так, чтобы не повредить ничему живому"... да, но пытаться-то ведь все равно надо. "На этом стоит мир", говоря словами все того же персонажа (Ученый из "Тени").Параноидальные ощущения настигли, когда я впервые прочел расхожую фразу о том, что "на джумле сайты делает только полный лошара"; они несколько усугубились, когда админы программистских форумов с покровительственной и мудрой улыбкой-смайликом все повидавших гуру начали уверять меня в том, что блог на Ruby in Rails они-де никому делать не посоветуют, "не надо"... ну, а дальше пошло-поехало. У вордпресса, как выяснилось, "даже приличного API нет, так уж исторически сложилось", да и вообще, "на CMS что-либо делать бессмысленно, грузят систему", и на любых "хреньворках" так же. Ruby, дескать, давно и прочно dead, а вот "создадим вам мега-портал на ультрасовременной платформе Битрикс" - это в тренде, это завсегда пожалуйста. "В команду профессиональных программистов, пишущих уникальный Artificial Intelligence на базе Neural Network срочно требуются middle- и senior- PHP-программисты" также надолго отложилось в памяти.Интересно, насколько отчетливо программисты Google представляют себе существование в живой природе такого языка программирования, PHP?Своеобразным итогом моего импровизированного исследования стало интернет-знакомство с гениальным программистом, пишущим "в облаке Google" удивительную нейронную сеть, предназначенную для медицинских исследований будущего... при попытке обнаружить в гитхабе новоявленного инженера ГаГарина хоть какие-то наброски нетленного творения - автор сего спича сумел найти там лишь парочку электронных книг по программированию для начинающих, плюс безграмотный скрипт, написанный рукой школьника, и на этом пришлось закончить. Впрочем, картинка к тому времени уже почти сложилась...В качестве резюме не самых веселых размышлений стало написание на основе фреймворка Ruby on Rails некоего скрипта, вполне подходящего под определение CMS, кодом которого и хочу сегодня поделиться на страницах Хабра с вами. Шуточный заголовок "Joomla on Rails" призван передать горячее желание автора написать что-то вполне удобное, удобоваримое и функциональное, в пику расхожему слогану "не делайте блогов на рельсах"; также в очередной раз порекламировать отличный конструктор для профессиональных веб-программистов, коим по праву можно назвать фреймворк Ruby on Rails.Примеры такого рода статей / туториалов имеют место быть в Сети, разумеется, но у этого материала будет с ними критичное отличие. Заключающееся в том, что уровень сложности и, соответственно, реализованный функционал окажется значительно выше, чем во многих известных и популярных примерах... нет, ну а зачем повторять то, что уже было. Перечень свойств блога в общих чертах (на данный момент) я бы описал вот так:
- Удобная панель администрирования сайта
- Баннерная реклама с геотаргетингом
- Текстовый редактор
- Встроенная аналитика посещений
- Категории
- Статьи
- Настраиваемая пагинация списка статей и тегов
- Контактная форма AJAX
- Комментарии AJAX
- Премодерация комментариев по-умолчанию
- Уведомления о новых комментариях по электронной почте
- Возможность хранить изображения в base64, также с использованием Active Storage (локальное хранилище либо AWS S3)
- Предварительный просмотр изображения (various preview options can be passed to the Active Storage variant method)
- Теги
- Мета-теги
- Погода по IP на карте Google
- RSS
- User-Friendly URLs
- Sitemap
- SlideShow
- Lightbox
- JavaScript Time Greeting
К сожалению, нет возможности в рамках одной статьи описать step-by-step процесс кодинга, получилось бы неоправданно много текста. Ограничусь тем, что кратко расскажу о нескольких основных моментах и опубликую ссылки на гитхаб и полнофункциональную демку... буде дополнительно возникнут вопросы - разумеется, по мере сил отвечу. Поехали.
Итак. В качестве дизайна использован бесплатный шаблон на основе Bootstrap 4, иконки FontAwesome5, вездесущий jQuery и новый (по-дефолту в Ruby on Rails 6) стандарт сборки фронтенда Webpacker:
# package.json
{
"name": "blog",
"private": true,
"dependencies": {
"@rails/actioncable": "^6.1.3-1",
"@rails/activestorage": "^6.1.3-1",
"@rails/ujs": "^6.1.3-1",
"@rails/webpacker": "5.4.0",
"bootstrap": "^4.6.0",
"jquery": "^3.6.0",
"popper.js": "^1.16.1",
"turbolinks": "^5.2.0"
},
"version": "0.1.0",
"devDependencies": {
"webpack-dev-server": "^3.11.2"
}
}
В основу формы публикации материалов положен следующий принцип: первые 5 из них отображаются в топ-меню, линки к остальным (и к первым пяти тоже) доступны на главной странице, включена пагинация. Опции которой всегда доступны для редактирования в конфиге kaminari:
# config/initializers/kaminari_config.rb
Kaminari.configure do |config|
config.default_per_page = 5
# config.max_per_page = nil
# config.window = 4
# config.outer_window = 0
# config.left = 0
# config.right = 0
# config.page_method_name = :page
# config.param_name = :page
# config.max_pages = nil
# config.params_on_first_page = false
end
Чуть забегая вперед, добавлю, что пагинация включена также для перечня материалов категории и тегов. И - сразу переходим к горячо любимому всеми социальными группами интернета SEO:Метатеги. При написании очередного материала вы имеете возможность, см. скриншот выше, создать description и keywords метатеги, и метатег description при создании категории. Разумеется, все это может быть в любой момент отредактировано либо сделано позже; к слову, любую статью блога необходимо привязать к той или иной категории, но вот публиковать ли категорию или нет - дело сугубо ваше, материал будет доступен для чтения в любом случае. Что касается метатега title, он будет сформирован автоматически, по принципу <Имя блога> | <Название статьи>, причем имя блога единожды определено в application.html.erb:
# app/views/layouts/application.html.erb
<head>
<%= display_meta_tags site: 'My Blog on Rails' %>
</head>
Так происходит для всех страниц статей и страниц категорий, на других динамически формируемых страницах (странички тегов, например) title и description (keywords в данном случае без надобности, но, при желании, возможно включить и его) окажутся сформированы исходя из метода, доступного для редактирования в контроллере:
# app/controllers/application_controller.rb
def metatags
set_meta_tags title: 'Building a Blog with Ruby on Rails',
description: 'Your Guide To Content Management System For Ruby on Rails'
end
Собственно говоря, достаточно определить в том или ином контроллере @page_title и @page_description (например), чтобы тут же получить эти метатеги на страничке, при этом вносить изменения в HTML не потребуется... это и есть, так сказать, магия Ruby on Rails.Доступны для использования, например, следующие методы:
<% title 'Member Login' %>
<% description 'Member login page.' %>
<% keywords 'Site, Login, Members' %>
<% nofollow %>
<% noindex %>
<% refresh 3 %>
, но не только; вы можете использовать, например, :canonical, :og (Open Graph), :twitter и другие. Подробнее на страничке kpumuk/meta-tags.Sitemap, карта сайта. Чтобы сформировать в директории public архив sitemap.xml.gz (или обновить, ввиду публикации нового контента), достаточно запустить в консоли эту команду:
rails sitemap:refresh
При этом Google и Bing будут уведомлены о доступности новой карты сайта. Возможно и добавление в ping иных поисковых систем, подробнее см. описание gem 'sitemap_generator', использованного для реализации sitemap блога. Возможен, разумеется, и автоматический, из крона запуск по расписанию обновления карты сайта; при использовании Whenever синтаксис способен выглядеть совсем несложно:
# config/schedule.rb
every 1.day, :at => '5:00 am' do
rake "-s sitemap:refresh"
end
Помимо динамически созданных страниц, включаем в карту сайта и парочку статических (на демке это Analytics и Contacts):
# config/sitemap.rb
SitemapGenerator::Sitemap.default_host = ENV['DOMAIN_NAME']
SitemapGenerator::Sitemap.create do
Post.find_each do |content|
add post_path(content), :lastmod => content.updated_at
end
add analytics_path, :priority => 0.5, :changefreq => 'weekly'
add contacts_path, :priority => 0.5, :changefreq => 'weekly'
end
Путь к карте сайта прописан в robots.txt. Те, кто решит потестировать этот блог на рельсах - не забудьте изменить название домена:
# public/robots.txt
User-agent: *
Disallow:
Sitemap: http://mstp.herokuapp.com/sitemap.xml.gz
Все превью изображений постов и категорий кликабельны, по клику открываются в лайтбоксе. Кроме того, Active Storage variants позволяет указать фильтры, чем мы и воспользуемся, определив kuwahara для статей и/или monochrome для категорий:
def preview_post(i)
if i.images.attached? && !current_page?(root_path)
tag.div class: 'preview' do
link_to i.images.first, 'data-lightbox' => 'preview' do
image_tag i.images.first.variant(
resize_to_fill: [400, 300], kuwahara: '3%'
)
end
end
end
end
Тегирование. При формировании или редактировании материала вы имеете возможность указать (снова см. скриншот выше) теги, через запятую.Сразу подчеркну, в данном случае использование acts-as-taggable-on далеко не исчерпывает весь заложенный автором джема функционал. Нет, относительно тегирования задачи у меня были самые скромные: теги создаются в Active Admin при создании статьи либо на вкладке Tags (там же могут быть и удалены/отредактированы в дальнейшем), и отображаются на фронте блога, на страничке материала в нижней его части вкупе с цифрой, характеризующей количество статей, отмеченных данным тегом. Каждый тег кликабелен, по клику отображается динамически формируемая страничка тега с также кликабельным перечнем заголовков статей.Показываем теги в статьях:
# posts_controller
def show
@post = Post.find(params[:id])
end
# app/views/posts/show.html.erb
<% @post.tag_list.each do |tag| %>
<%= tags(tag) %>
<% end %>
# helper
def tags(tag)
link_to (tag.to_s +
' (' +
Post.tagged_with(tag).count.to_s +
')'),
tag_url(tag),
class: 'badge badge-secondary'
end
Формируем страничку тега с перечнем статей:
# tags_controller.rb
def show
@posts = Post.tagged_with(params[:id])
end
# app/views/tags/show.html.erb
<% @posts.each do |i| %>
<%= link_to i.title, {controller: "posts", action: "show", id: i.id} %>
<% end %>
Не забываем про маршруты. Например, как-то так:
# routes.rb
resources :posts do
resources :comments
end
resources :tags, only: [:show]
Пожалуй, уже многовато кода, да? ОК, далее постараюсь, насколько смогу, урезаться... программисты и без того разберутся, для остальных же и так и эдак не имеет смысла, вы правы.SEO-Friendly URLs, дружелюбные / человекопонятные адреса ЧПУ страниц. Url страницы формируется исходя из заголовка, кириллица при этом автоматически транслитерируется в латиницу. Это касается статей и категорий:
# Gemfile
gem 'friendly_id', '~> 5.4.0'
gem 'babosa'
RSS. Этот Blog on Rails автоматически формирует валидную RSS-ленту, доступную (иконка bootstrap 4) на всех страницах сайта. Несколько портят впечатление длинные коды изображений, сохраненных в base64. Дело в том, что данная CMS изначально ориентирована на хостинг (облачная PaaS-платформа) Heroku, с его хитроумной виртуальной файловой системой, отсюда и base64. Не представляет большой сложности, к слову, при работе в используемом редакторе - Quill Editor - сохранение изображений классическим способом, кому оно надо - велкам на страничку джема за инструкциями по установке ImageUploader plugin. Но, возможно, вы удовлетворитесь уже реализованной возможностью альтернативной загрузки изображений на сервера Amazon S3? Подробнее о процедуре подобной реализации в этом материале.
Остановлюсь на слайдере, который может быть включен на главной (и не только) странице. Регистрируем слайдер в ActiveAdmin, на основе которого построена административная панель блога:
ActiveAdmin.register Slider do
permit_params :published_at, :name, images: []
scope :all
scope :published
scope :unpublished
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])
slider.images.purge_later
redirect_to admin_slider_path(slider)
end
form do |f|
f.inputs 'Slider' do
f.input :name
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 do |img|
span do
image_tag img.variant(resize_to_limit: [100, 100])
end
end
end
row :name
row :created_at
row :updated_at
row :published_at
end
end
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
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
В качестве редактора текста попробуем использовать Quill Rich Text Editor (gem 'activeadmin_quill_editor'), инициализировав следующим образом (покажу всю вкладку ввода материала):
form do |f|
f.inputs 'Article' do
f.input :category
f.input :tag_list, input_html: { value: f.object.tag_list.join(', ') }, label: 'Tags (separated by commas)'
f.input :title, label: 'Title (70 characters maximum)'
f.input :description, label: 'Description (160 characters maximum)'
f.input :keywords, label: 'Keywords (5 - 10 words)'
f.input :text, as: :quill_editor, input_html: { data:
{ options:
{ modules:
{ toolbar:
[%w[bold italic underline strike],
%w[blockquote code-block],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'align': [] }],
['link'],
[{ 'size': ['small', false, 'large', 'huge'] }],
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'indent': '-1' }, { 'indent': '+1' }],
[{ 'direction': 'rtl' }],
[{ 'color': [] }, { 'background': [] }],
[{ 'font': [] }],
['clean'],
['image'],
['video']] },
theme: 'snow' } } }, label: 'The content of the article'
f.input :images, as: :file, input_html: { multiple: true }, label: 'Add illustrations to the article'
end
f.actions
end
Результат таков, как на скриншоте в начале статьи.Напоследок упомяну, что в качестве статистики визитов сделана попытка отказаться от Google Analytics и Яндекс Метрика, и использовать Ahoy - Simple, powerful, first-party analytics for Rails. Не бог весть что, конечно, но для многих сайтовладельцев подобного решения более чем достаточно (сеошники, погодите скрипеть зубами). В качестве примера - страничка аналитики, куда в целях демонстрации выведено четыре чарта, отображающих данные посещений последней недели из базы данных.Формируем статистику по странам:
@locations = Ahoy::Visit.all.group(:country).count
, заменяя, при необходимости, nil на строку:
@locations = Ahoy::Visit.all.group(:country).count.map { |k, v| [k ||= 'undefined', v] }
Все то же самое относительно группировки по городам:
Ahoy::Visit.all.group(:city).count
, ну, или как посчитаете нужным; следующие фрагменты кода прояснят ситуацию:
@visits = Ahoy::Visit.all
@events = Ahoy::Event.all
<% @visits.each do |visit| %>
Visit Number: <%= visit.id %><br>
Visit Token: <%= visit.visit_token %><br>
Visitor Token: <%= visit.visitor_token %><br>
IP: <%= visit.ip %><br>
User Agent: <%= visit.user_agent %><br>
Referrer: <%= visit.referrer %><br>
Referring domain: <%= visit.referring_domain %><br>
Device Type: <%= visit.device_type %><br>
Country: <%= visit.country %><br>
Region: <%= visit.region %><br>
City: <%= visit.city %><br>
Latitude: <%= visit.latitude %><br>
Longitude: <%= visit.longitude %><br>
User ID: <%= visit.user_id %><br>
<% end %>
Учтите, веб-аналитика Ahoy способна учитывать довольно многое, вплоть до кликов и переходов по ссылкам. Рекомендую.Ну и, разумеется, в свой блог на рельсах вы сможете добавлять любые фичи, которые посчитаете нужным. Я, например, добавил отображение картинок в верхней части сайта в зависимости от геотергетинга посетителя блога, использовав механизм определения местоположения по IP все того же Ahoy. Вот как-то так:
class GetImages
def self.get_random_banner(country)
x = get_country(country)
File.join('/images', x, Dir.children(File.join(Rails.root, 'public', 'images', x)).sample)
end
def self.get_country(country)
if dir_names.include? country
country
else
'other'
end
end
def self.dir_names
target_folder_path = File.join(Rails.root, 'public', 'images')
Dir.children(target_folder_path)
end
end
...впрочем, всегда возможны варианты. Enjoy! :)P.S. Установка и использование этого блога не требуют ни знания Ruby / Rails / PostgreSQL, ни вообще умения с ними обращаться, ни даже их наличия на вашем ПК. Вам понадобятся всего только установленный git, ну и еще бесплатный аккаунт на Heroku, + зарегистрировать акк на AWS (будет работать бесплатно, или почти бесплатно, в течение года). Просто следуйте инструкциям ReadMe гитхаба, ссылка в начале статьи. Буду рад, если отпишитесь о впечатлениях.
===========
Источник:
habr.com
===========
Похожие новости:
- [Ruby, Ruby on Rails] Каперство в IT. В подражание Киплингу
- [Ruby, Ruby on Rails] WorkerKiller
- [Ruby, Ruby on Rails, Google Cloud Platform] Веб-клиент Google Cloud Text to Speech за завтраком в бастионе Сен-Жерве
- [Ruby, Google Chrome, Ruby on Rails] Генерация картинок в коде
- [Ruby on Rails] Hyperstack vs Hotwire (перевод) (перевод)
- [Информационная безопасность, Системы управления версиями, Управление продуктом] Как мы устранили редкую ошибку, из-за которой пришлось разлогинить всех пользователей Github (перевод)
- [Ruby, Ruby on Rails, Администрирование баз данных, Микросервисы] Синхронизация баз данных между монолитом и микросервисами с помощью Kafka. Наше решение
- [Ruby, Ruby on Rails] Как перейти с secrets на credentials (Ruby on Rails) (перевод)
- [Информационная безопасность, Ruby on Rails, CTF] HackTheBox. Прохождение Jewel. RCE в Ruby on Rails, sudo и google authenticator, выполнение кода в gem
- [Ruby, Ruby on Rails] Как добавить React-компонент в Active Admin
Теги для поиска: #_ruby_on_rails, #_blogs._blogi (blogs. блоги), #_ruby_on_rails
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:12
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Рунет производит на меня (и не только в контексте веб-программирования) крайне противоречивое впечатление. Возможно, так и должно быть, типа "Нью-Йорк - город контрастов"? - по крайней мере, та полупрофессиональная и пестрая интернет-тусовка, к которой обычно приходят новички, мечтающие выучиться на веб-программиста. Говоря словами героя пьесы Евгения Шварца - "очень трудно будет все это распутать, разобрать и привести в порядок так, чтобы не повредить ничему живому"... да, но пытаться-то ведь все равно надо. "На этом стоит мир", говоря словами все того же персонажа (Ученый из "Тени").Параноидальные ощущения настигли, когда я впервые прочел расхожую фразу о том, что "на джумле сайты делает только полный лошара"; они несколько усугубились, когда админы программистских форумов с покровительственной и мудрой улыбкой-смайликом все повидавших гуру начали уверять меня в том, что блог на Ruby in Rails они-де никому делать не посоветуют, "не надо"... ну, а дальше пошло-поехало. У вордпресса, как выяснилось, "даже приличного API нет, так уж исторически сложилось", да и вообще, "на CMS что-либо делать бессмысленно, грузят систему", и на любых "хреньворках" так же. Ruby, дескать, давно и прочно dead, а вот "создадим вам мега-портал на ультрасовременной платформе Битрикс" - это в тренде, это завсегда пожалуйста. "В команду профессиональных программистов, пишущих уникальный Artificial Intelligence на базе Neural Network срочно требуются middle- и senior- PHP-программисты" также надолго отложилось в памяти.Интересно, насколько отчетливо программисты Google представляют себе существование в живой природе такого языка программирования, PHP?Своеобразным итогом моего импровизированного исследования стало интернет-знакомство с гениальным программистом, пишущим "в облаке Google" удивительную нейронную сеть, предназначенную для медицинских исследований будущего... при попытке обнаружить в гитхабе новоявленного инженера ГаГарина хоть какие-то наброски нетленного творения - автор сего спича сумел найти там лишь парочку электронных книг по программированию для начинающих, плюс безграмотный скрипт, написанный рукой школьника, и на этом пришлось закончить. Впрочем, картинка к тому времени уже почти сложилась...В качестве резюме не самых веселых размышлений стало написание на основе фреймворка Ruby on Rails некоего скрипта, вполне подходящего под определение CMS, кодом которого и хочу сегодня поделиться на страницах Хабра с вами. Шуточный заголовок "Joomla on Rails" призван передать горячее желание автора написать что-то вполне удобное, удобоваримое и функциональное, в пику расхожему слогану "не делайте блогов на рельсах"; также в очередной раз порекламировать отличный конструктор для профессиональных веб-программистов, коим по праву можно назвать фреймворк Ruby on Rails.Примеры такого рода статей / туториалов имеют место быть в Сети, разумеется, но у этого материала будет с ними критичное отличие. Заключающееся в том, что уровень сложности и, соответственно, реализованный функционал окажется значительно выше, чем во многих известных и популярных примерах... нет, ну а зачем повторять то, что уже было. Перечень свойств блога в общих чертах (на данный момент) я бы описал вот так:
Итак. В качестве дизайна использован бесплатный шаблон на основе Bootstrap 4, иконки FontAwesome5, вездесущий jQuery и новый (по-дефолту в Ruby on Rails 6) стандарт сборки фронтенда Webpacker: # package.json
{ "name": "blog", "private": true, "dependencies": { "@rails/actioncable": "^6.1.3-1", "@rails/activestorage": "^6.1.3-1", "@rails/ujs": "^6.1.3-1", "@rails/webpacker": "5.4.0", "bootstrap": "^4.6.0", "jquery": "^3.6.0", "popper.js": "^1.16.1", "turbolinks": "^5.2.0" }, "version": "0.1.0", "devDependencies": { "webpack-dev-server": "^3.11.2" } } # config/initializers/kaminari_config.rb
Kaminari.configure do |config| config.default_per_page = 5 # config.max_per_page = nil # config.window = 4 # config.outer_window = 0 # config.left = 0 # config.right = 0 # config.page_method_name = :page # config.param_name = :page # config.max_pages = nil # config.params_on_first_page = false end # app/views/layouts/application.html.erb
<head> <%= display_meta_tags site: 'My Blog on Rails' %> </head> # app/controllers/application_controller.rb
def metatags set_meta_tags title: 'Building a Blog with Ruby on Rails', description: 'Your Guide To Content Management System For Ruby on Rails' end <% title 'Member Login' %>
<% description 'Member login page.' %> <% keywords 'Site, Login, Members' %> <% nofollow %> <% noindex %> <% refresh 3 %> rails sitemap:refresh
# config/schedule.rb
every 1.day, :at => '5:00 am' do rake "-s sitemap:refresh" end # config/sitemap.rb
SitemapGenerator::Sitemap.default_host = ENV['DOMAIN_NAME'] SitemapGenerator::Sitemap.create do Post.find_each do |content| add post_path(content), :lastmod => content.updated_at end add analytics_path, :priority => 0.5, :changefreq => 'weekly' add contacts_path, :priority => 0.5, :changefreq => 'weekly' end # public/robots.txt
User-agent: * Disallow: Sitemap: http://mstp.herokuapp.com/sitemap.xml.gz def preview_post(i)
if i.images.attached? && !current_page?(root_path) tag.div class: 'preview' do link_to i.images.first, 'data-lightbox' => 'preview' do image_tag i.images.first.variant( resize_to_fill: [400, 300], kuwahara: '3%' ) end end end end # posts_controller
def show @post = Post.find(params[:id]) end # app/views/posts/show.html.erb <% @post.tag_list.each do |tag| %> <%= tags(tag) %> <% end %> # helper def tags(tag) link_to (tag.to_s + ' (' + Post.tagged_with(tag).count.to_s + ')'), tag_url(tag), class: 'badge badge-secondary' end # tags_controller.rb
def show @posts = Post.tagged_with(params[:id]) end # app/views/tags/show.html.erb <% @posts.each do |i| %> <%= link_to i.title, {controller: "posts", action: "show", id: i.id} %> <% end %> # routes.rb
resources :posts do resources :comments end resources :tags, only: [:show] # Gemfile
gem 'friendly_id', '~> 5.4.0' gem 'babosa' Остановлюсь на слайдере, который может быть включен на главной (и не только) странице. Регистрируем слайдер в ActiveAdmin, на основе которого построена административная панель блога: ActiveAdmin.register Slider do
permit_params :published_at, :name, images: [] scope :all scope :published scope :unpublished 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]) slider.images.purge_later redirect_to admin_slider_path(slider) end form do |f| f.inputs 'Slider' do f.input :name 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 do |img| span do image_tag img.variant(resize_to_limit: [100, 100]) end end end row :name row :created_at row :updated_at row :published_at end end 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 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 form do |f|
f.inputs 'Article' do f.input :category f.input :tag_list, input_html: { value: f.object.tag_list.join(', ') }, label: 'Tags (separated by commas)' f.input :title, label: 'Title (70 characters maximum)' f.input :description, label: 'Description (160 characters maximum)' f.input :keywords, label: 'Keywords (5 - 10 words)' f.input :text, as: :quill_editor, input_html: { data: { options: { modules: { toolbar: [%w[bold italic underline strike], %w[blockquote code-block], [{ 'list': 'ordered' }, { 'list': 'bullet' }], [{ 'align': [] }], ['link'], [{ 'size': ['small', false, 'large', 'huge'] }], [{ 'header': [1, 2, 3, 4, 5, 6, false] }], [{ 'indent': '-1' }, { 'indent': '+1' }], [{ 'direction': 'rtl' }], [{ 'color': [] }, { 'background': [] }], [{ 'font': [] }], ['clean'], ['image'], ['video']] }, theme: 'snow' } } }, label: 'The content of the article' f.input :images, as: :file, input_html: { multiple: true }, label: 'Add illustrations to the article' end f.actions end @locations = Ahoy::Visit.all.group(:country).count
@locations = Ahoy::Visit.all.group(:country).count.map { |k, v| [k ||= 'undefined', v] }
Ahoy::Visit.all.group(:city).count
@visits = Ahoy::Visit.all
@events = Ahoy::Event.all <% @visits.each do |visit| %> Visit Number: <%= visit.id %><br> Visit Token: <%= visit.visit_token %><br> Visitor Token: <%= visit.visitor_token %><br> IP: <%= visit.ip %><br> User Agent: <%= visit.user_agent %><br> Referrer: <%= visit.referrer %><br> Referring domain: <%= visit.referring_domain %><br> Device Type: <%= visit.device_type %><br> Country: <%= visit.country %><br> Region: <%= visit.region %><br> City: <%= visit.city %><br> Latitude: <%= visit.latitude %><br> Longitude: <%= visit.longitude %><br> User ID: <%= visit.user_id %><br> <% end %> class GetImages
def self.get_random_banner(country) x = get_country(country) File.join('/images', x, Dir.children(File.join(Rails.root, 'public', 'images', x)).sample) end def self.get_country(country) if dir_names.include? country country else 'other' end end def self.dir_names target_folder_path = File.join(Rails.root, 'public', 'images') Dir.children(target_folder_path) end end =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:12
Часовой пояс: UTC + 5