Joomla on Rails, or features of national web programming

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.








All Articles