Runet makes an extremely contradictory impression on me (and not only in the context of web programming). Perhaps this is how it should be, like "New York is a city of contrasts"? - at least that semi-professional and colorful Internet get-together, to which beginners usually come who dream of learning to become a web programmer. In the words of the hero of the play, Yevgeny Schwartz, "it will be very difficult to unravel all this, disassemble and put it in order so as not to damage anything living" ... yes, but you still have to try. "The world stands on this", in the words of the same character (Scientist from "Shadow").
, , " "; , - , 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! :)
PS Installing and using this blog does not require any knowledge of Ruby / Rails / PostgreSQL , nor any knowledge of how to use them, nor even having them on your PC. All you need is just installed git , and also a free account on Heroku , + register an account on AWS (it will work for free, or almost free, for a year). Just follow the GitHub ReadMe instructions, link at the beginning of the article.
I would be glad if you can unsubscribe about your impressions.