Joomla on Rails, o características de la programación web nacional

Runet me causa una impresión extremadamente contradictoria (y no solo en el contexto de la programación web). ¿Quizás así debería ser, como "Nueva York es una ciudad de contrastes"? - al menos ese encuentro de Internet semiprofesional y colorido, al que suelen acudir los principiantes que sueñan con aprender a ser programadores web. En palabras del héroe de la obra, Yevgeny Schwartz, "será muy difícil desentrañar todo esto, desmontarlo y ponerlo en orden para no dañar nada vivo" ... sí, pero aún hay que intentarlo. "El mundo se apoya en esto", en palabras del mismo personaje (Científico de "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! :)





PD La instalación y el uso de este blog no requiere ningún conocimiento de Ruby / Rails / PostgreSQL , ni ningún conocimiento de cómo usarlos, ni siquiera tenerlos en su PC. Todo lo que necesita es instalar git , y también una cuenta gratuita en Heroku , + registrar una cuenta en AWS (funcionará gratis, o casi gratis, durante un año). Simplemente siga las instrucciones Léame de GitHub, enlace al principio del artículo.





Me alegraría si pudiera darse de baja de sus impresiones.








All Articles