cambiar el algoritmo de ordenamiento

para poder respetar el orden de más nuevo a más antiguo, el número de
orden se convirtió en decreciente (de más alto a más bajo).

además, encontramos algunos temas de performance como guardar solo los
artículos que cambiaron y no todos.

se graban los cambios sin validarlos, es decir, solo el cambio de orden.
This commit is contained in:
f 2019-12-11 17:05:31 -03:00
parent 57457cfcc8
commit 0c81809edf
No known key found for this signature in database
GPG key ID: 2AE5A13E321F953D
11 changed files with 105 additions and 82 deletions

View file

@ -12,7 +12,7 @@ class PostsController < ApplicationController
@layout = params.dig(:layout).try :to_sym @layout = params.dig(:layout).try :to_sym
# TODO: Aplicar policy_scope # TODO: Aplicar policy_scope
@posts = @site.posts(lang: I18n.locale) @posts = @site.posts(lang: I18n.locale)
@posts.sort_by! :order, :date @posts.sort_by!(:order, :date).reverse!
end end
def show def show

View file

@ -29,7 +29,11 @@ document.addEventListener('turbolinks:load', () => {
onlyBody: true, onlyBody: true,
dragHandler: '.handle' dragHandler: '.handle'
}).on('drop', (from, to, el, mode) => { }).on('drop', (from, to, el, mode) => {
$('.reorder').val((i,v) => i); Array.from(document.querySelectorAll('.reorder'))
$('.submit-reorder').removeClass('d-none'); .reverse()
.map((o,i) => o.value = i);
Array.from(document.querySelectorAll('.submit-reorder'))
.map(s => s.classList.remove('d-none'));
}); });
}) })

View file

@ -2,8 +2,9 @@
# Un campo de orden # Un campo de orden
class MetadataOrder < MetadataTemplate class MetadataOrder < MetadataTemplate
# El valor es 0 porque estamos ordenando por orden y fecha # El valor según la posición del post en la relación ordenada por
# fecha, a fecha más alta, posición más alta
def default_value def default_value
0 site.posts(lang: post.lang.value).sort_by(:date).index(post)
end end
end end

View file

@ -15,6 +15,8 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
# Valores posibles, busca todos los valores actuales en otros # Valores posibles, busca todos los valores actuales en otros
# artículos del mismo sitio # artículos del mismo sitio
#
# TODO: Implementar lang!
def values def values
site.everything_of(name) site.everything_of(name)
end end

View file

@ -156,8 +156,8 @@ class Post < OpenStruct
# Guarda los cambios # Guarda los cambios
# rubocop:disable Metrics/CyclomaticComplexity # rubocop:disable Metrics/CyclomaticComplexity
def save(validation = true) def save(validate: true)
return false if validation && !valid? return false if validate && !valid?
# Salir si tenemos que cambiar el nombre del archivo y no pudimos # Salir si tenemos que cambiar el nombre del archivo y no pudimos
return false if !new? && path_changed? && !update_path! return false if !new? && path_changed? && !update_path!
return false unless save_attributes! return false unless save_attributes!
@ -197,12 +197,6 @@ class Post < OpenStruct
# Detecta si el artículo es válido para guardar # Detecta si el artículo es válido para guardar
def valid? def valid?
validate
errors.blank?
end
# Requisitos para que el post sea válido
def validate
self.errors = {} self.errors = {}
layout.metadata.keys.map(&:to_sym).each do |metadata| layout.metadata.keys.map(&:to_sym).each do |metadata|
@ -210,8 +204,9 @@ class Post < OpenStruct
errors[metadata] = template.errors unless template.valid? errors[metadata] = template.errors unless template.valid?
end end
errors.blank?
end end
alias validate! validate
# Guarda los cambios en el archivo destino # Guarda los cambios en el archivo destino
def write def write

View file

@ -31,15 +31,18 @@ class PostRelation < Array
post post
end end
alias sort_by_generic sort_by
alias sort_by_generic! sort_by! alias sort_by_generic! sort_by!
# Permite ordenar los artículos por sus atributos # Permite ordenar los artículos por sus atributos
# #
# XXX: Prestar atención cuando estamos mezclando artículos con # XXX: Prestar atención cuando estamos mezclando artículos con
# diferentes tipos de atributos. # diferentes tipos de atributos.
def sort_by!(*attrs) def sort_by(*attrs)
sort_by_generic! do |post| sort_by_generic do |post|
attrs.map do |attr| attrs.map do |attr|
# TODO: detectar el tipo de atributo faltante y obtener el valor
# por defecto para hacer la comparación
return 0 unless post.attributes.include? attr return 0 unless post.attributes.include? attr
post.public_send(attr).value post.public_send(attr).value
@ -47,6 +50,10 @@ class PostRelation < Array
end end
end end
def sort_by!(*attrs)
replace sort_by(*attrs)
end
alias find_generic find alias find_generic find
# Encontra un post por su id convertido a SHA1 # Encontra un post por su id convertido a SHA1
@ -65,8 +72,10 @@ class PostRelation < Array
end end
# Intenta guardar todos y devuelve true si pudo # Intenta guardar todos y devuelve true si pudo
def save_all def save_all(validate: true)
map(&:save).all? map do |post|
post.save(validate: validate)
end.all?
end end
private private

View file

@ -79,7 +79,7 @@ class Site
end end
# Guardamos los cambios # Guardamos los cambios
unless doc.save(false) unless doc.save(validate: false)
log.write "#{doc.path.relative} no se pudo guardar\n" log.write "#{doc.path.relative} no se pudo guardar\n"
end end

View file

@ -47,18 +47,23 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
def reorder def reorder
posts = site.posts(lang: lang) posts = site.posts(lang: lang)
reorder = params.require(:post).permit(reorder: {}).try(:[], :reorder) reorder = params.require(:post).permit(reorder: {}).try(:[], :reorder)
modified = PostRelation.new(site: site)
files = reorder.keys.map do |id| files = reorder.keys.map do |id|
post = posts.find(id, sha1: true) post = posts.find(id, sha1: true)
next unless post.attributes.include? :order order = reorder[id].to_i
post.usuaries << usuarie next unless post.attributes.include? :order
post.order.value = reorder[id].to_i next if post.order.value == order
modified << post
post.order.value = order
post.path.absolute post.path.absolute
end.compact end.compact
# TODO: Implementar transacciones! # TODO: Implementar transacciones!
posts.save_all && commit(action: :reorder, file: files) modified.save_all(validate: false) &&
commit(action: :reorder, file: files)
end end
private private

View file

@ -25,11 +25,11 @@
%section.col %section.col
= render 'layouts/flash' = render 'layouts/flash'
- if @posts.present? - if @posts.empty?
.row %h2= t('posts.none')
.col - else
= form_tag site_posts_reorder_path, method: :post do = form_tag site_posts_reorder_path, method: :post do
= submit_tag t('posts.reorder'), class: 'btn submit-reorder d-none' = submit_tag t('posts.reorder'), class: 'btn submit-reorder'
-# TODO: Permitir cambiar el idioma -# TODO: Permitir cambiar el idioma
%table.table.table-condensed.table-draggable %table.table.table-condensed.table-draggable
%tbody %tbody
@ -47,8 +47,9 @@
%td %td
.handle .handle
= image_tag 'arrows-alt-v.svg' = image_tag 'arrows-alt-v.svg'
-# Orden más alto es mayor prioridad
= hidden_field 'post[reorder]', post.sha1, = hidden_field 'post[reorder]', post.sha1,
value: i, class: 'reorder' value: @posts.length - i, class: 'reorder'
%td %td
%small %small
= link_to post.layout.name.to_s.humanize, = link_to post.layout.name.to_s.humanize,
@ -82,5 +83,3 @@
class: 'btn', class: 'btn',
method: :delete, method: :delete,
data: { confirm: t('posts.confirm_destroy') } data: { confirm: t('posts.confirm_destroy') }
- else
%h2= t('posts.none')

View file

@ -23,3 +23,11 @@ otra vez.
Lo más controlado sería enviar exactamente el id del post con su nueva Lo más controlado sería enviar exactamente el id del post con su nueva
ubicación en el orden. Esta es la implementación anterior. ubicación en el orden. Esta es la implementación anterior.
***
El orden es descendiente (fechas más nuevas primero), pero el orden que
estuvimos usando es ascendientes (números más bajos primero). Es más
simple invertir la lógica y hacer todo el orden descendiente. Para eso
los artículos más nuevos tienen que tener el número de orden
correspondiente a la posición en el array ordenado por fecha.

View file

@ -66,7 +66,7 @@ class PostTest < ActiveSupport::TestCase
test 'se pueden guardar sin validar' do test 'se pueden guardar sin validar' do
assert @post.valid? assert @post.valid?
@post.title.value = '' @post.title.value = ''
assert @post.save(false) assert @post.save(validate: false)
end end
test 'se pueden guardar los cambios' do test 'se pueden guardar los cambios' do