mirror of
https://0xacab.org/sutty/sutty
synced 2025-02-22 13:51:46 +00:00
Merge branch 'rails' into actualizacion-de-cuidados
This commit is contained in:
commit
443950819f
18 changed files with 192 additions and 66 deletions
1
Gemfile
1
Gemfile
|
@ -69,6 +69,7 @@ gem 'terminal-table'
|
||||||
gem 'validates_hostname'
|
gem 'validates_hostname'
|
||||||
gem 'webpacker'
|
gem 'webpacker'
|
||||||
gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git'
|
gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git'
|
||||||
|
gem 'kaminari'
|
||||||
|
|
||||||
# database
|
# database
|
||||||
gem 'hairtrigger'
|
gem 'hairtrigger'
|
||||||
|
|
13
Gemfile.lock
13
Gemfile.lock
|
@ -309,6 +309,18 @@ GEM
|
||||||
jekyll-write-and-commit-changes (0.2.0)
|
jekyll-write-and-commit-changes (0.2.0)
|
||||||
jekyll (~> 4)
|
jekyll (~> 4)
|
||||||
rugged (~> 1)
|
rugged (~> 1)
|
||||||
|
kaminari (1.2.1)
|
||||||
|
activesupport (>= 4.1.0)
|
||||||
|
kaminari-actionview (= 1.2.1)
|
||||||
|
kaminari-activerecord (= 1.2.1)
|
||||||
|
kaminari-core (= 1.2.1)
|
||||||
|
kaminari-actionview (1.2.1)
|
||||||
|
actionview
|
||||||
|
kaminari-core (= 1.2.1)
|
||||||
|
kaminari-activerecord (1.2.1)
|
||||||
|
activerecord
|
||||||
|
kaminari-core (= 1.2.1)
|
||||||
|
kaminari-core (1.2.1)
|
||||||
kramdown (2.3.1)
|
kramdown (2.3.1)
|
||||||
rexml
|
rexml
|
||||||
kramdown-parser-gfm (1.1.0)
|
kramdown-parser-gfm (1.1.0)
|
||||||
|
@ -669,6 +681,7 @@ DEPENDENCIES
|
||||||
jekyll-data!
|
jekyll-data!
|
||||||
jekyll-images
|
jekyll-images
|
||||||
jekyll-include-cache
|
jekyll-include-cache
|
||||||
|
kaminari
|
||||||
letter_opener
|
letter_opener
|
||||||
listen (>= 3.0.5, < 3.2)
|
listen (>= 3.0.5, < 3.2)
|
||||||
loaf
|
loaf
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -108,7 +108,6 @@ ota-js: assets ## Actualizar Javascript en el nodo delegado
|
||||||
|
|
||||||
ota: ## Actualizar Rails en el nodo delegado
|
ota: ## Actualizar Rails en el nodo delegado
|
||||||
umask 022; git format-patch $(commit)
|
umask 022; git format-patch $(commit)
|
||||||
scp ./0*.patch $(delegate):/tmp/
|
|
||||||
ssh $(delegate) mkdir -p /tmp/patches-$(commit)/
|
ssh $(delegate) mkdir -p /tmp/patches-$(commit)/
|
||||||
scp ./0*.patch $(delegate):/tmp/patches-$(commit)/
|
scp ./0*.patch $(delegate):/tmp/patches-$(commit)/
|
||||||
scp ./ota.sh $(delegate):/tmp/
|
scp ./ota.sh $(delegate):/tmp/
|
||||||
|
|
|
@ -22,7 +22,8 @@ class PostsController < ApplicationController
|
||||||
|
|
||||||
# XXX: Cada vez que cambiamos un Post tocamos el sitio con lo que es
|
# XXX: Cada vez que cambiamos un Post tocamos el sitio con lo que es
|
||||||
# más simple saber si hubo cambios.
|
# más simple saber si hubo cambios.
|
||||||
if stale?([current_usuarie, site, filter_params])
|
return unless stale?([current_usuarie, site, filter_params])
|
||||||
|
|
||||||
# Todos los artículos de este sitio para el idioma actual
|
# Todos los artículos de este sitio para el idioma actual
|
||||||
@posts = site.indexed_posts.where(locale: locale)
|
@posts = site.indexed_posts.where(locale: locale)
|
||||||
# De este tipo
|
# De este tipo
|
||||||
|
@ -37,7 +38,6 @@ class PostsController < ApplicationController
|
||||||
# Filtrar los posts que les invitades no pueden ver
|
# Filtrar los posts que les invitades no pueden ver
|
||||||
@usuarie = site.usuarie? current_usuarie
|
@usuarie = site.usuarie? current_usuarie
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
authorize post
|
authorize post
|
||||||
|
@ -54,7 +54,7 @@ class PostsController < ApplicationController
|
||||||
|
|
||||||
def new
|
def new
|
||||||
authorize Post
|
authorize Post
|
||||||
@post = site.posts.build(lang: locale, layout: params[:layout])
|
@post = site.posts(lang: locale).build(layout: params[:layout])
|
||||||
|
|
||||||
breadcrumb I18n.t('loaf.breadcrumbs.posts.new', layout: @post.layout.humanized_name.downcase), ''
|
breadcrumb I18n.t('loaf.breadcrumbs.posts.new', layout: @post.layout.humanized_name.downcase), ''
|
||||||
end
|
end
|
||||||
|
@ -154,7 +154,9 @@ class PostsController < ApplicationController
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def filter_params
|
def filter_params
|
||||||
@filter_params ||= params.permit(:q, :category, :layout).to_h.select { |_, v| v.present? }
|
@filter_params ||= params.permit(:q, :category, :layout).to_hash.select do |_, v|
|
||||||
|
v.present?
|
||||||
|
end.transform_keys(&:to_sym)
|
||||||
end
|
end
|
||||||
|
|
||||||
def site
|
def site
|
||||||
|
|
|
@ -25,10 +25,19 @@ class MetadataBoolean < MetadataTemplate
|
||||||
# * false
|
# * false
|
||||||
# * true
|
# * true
|
||||||
def value
|
def value
|
||||||
return document.data.fetch(name.to_s, default_value) if self[:value].nil?
|
case self[:value]
|
||||||
return self[:value] unless self[:value].is_a? String
|
when NilClass
|
||||||
|
document.data.fetch(name.to_s, default_value)
|
||||||
|
when String
|
||||||
|
true_values.include? self[:value]
|
||||||
|
else
|
||||||
|
self[:value]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
self[:value] = true_values.include? self[:value]
|
# Siempre guardar el valor de este campo a menos que sea nulo
|
||||||
|
def empty?
|
||||||
|
value.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -56,7 +56,7 @@ class MetadataContent < MetadataTemplate
|
||||||
uri = URI element['src']
|
uri = URI element['src']
|
||||||
|
|
||||||
# No permitimos recursos externos
|
# No permitimos recursos externos
|
||||||
element.remove unless uri.hostname.end_with? Site.domain
|
element.remove unless uri.scheme == 'https' && uri.hostname.end_with?(Site.domain)
|
||||||
rescue URI::Error
|
rescue URI::Error
|
||||||
element.remove
|
element.remove
|
||||||
end
|
end
|
||||||
|
|
31
app/models/metadata_float.rb
Normal file
31
app/models/metadata_float.rb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Un campo numérico de punto flotante
|
||||||
|
class MetadataFloat < MetadataTemplate
|
||||||
|
# Nada
|
||||||
|
def default_value
|
||||||
|
super || nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
return true unless changed?
|
||||||
|
|
||||||
|
self[:value] = value.to_f
|
||||||
|
self[:value] = encrypt(value) if private?
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
# Indicarle al navegador que acepte números decimales
|
||||||
|
#
|
||||||
|
# @return [Float]
|
||||||
|
def step
|
||||||
|
0.05
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def decrypt(value)
|
||||||
|
super(value).to_f
|
||||||
|
end
|
||||||
|
end
|
24
app/models/metadata_predefined_value.rb
Normal file
24
app/models/metadata_predefined_value.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Un campo de texto seleccionado de una lista de valores posibles
|
||||||
|
class MetadataPredefinedValue < MetadataString
|
||||||
|
# Obtiene todos los valores desde el layout, en un formato compatible
|
||||||
|
# con options_for_select.
|
||||||
|
#
|
||||||
|
# @return [Hash]
|
||||||
|
def values
|
||||||
|
@values ||= layout.dig(:metadata, name, 'values', I18n.locale.to_s)&.invert || {}
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Solo permite almacenar los valores predefinidos.
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def sanitize(string)
|
||||||
|
v = super string
|
||||||
|
return '' unless values.values.include? v
|
||||||
|
|
||||||
|
v
|
||||||
|
end
|
||||||
|
end
|
|
@ -65,9 +65,6 @@ class Site < ApplicationRecord
|
||||||
|
|
||||||
accepts_nested_attributes_for :deploys, allow_destroy: true
|
accepts_nested_attributes_for :deploys, allow_destroy: true
|
||||||
|
|
||||||
# El sitio en Jekyll
|
|
||||||
attr_reader :jekyll
|
|
||||||
|
|
||||||
# XXX: Es importante incluir luego de los callbacks de :load_jekyll
|
# XXX: Es importante incluir luego de los callbacks de :load_jekyll
|
||||||
include Site::Index
|
include Site::Index
|
||||||
|
|
||||||
|
@ -180,29 +177,28 @@ class Site < ApplicationRecord
|
||||||
|
|
||||||
# Trae los datos del directorio _data dentro del sitio
|
# Trae los datos del directorio _data dentro del sitio
|
||||||
def data
|
def data
|
||||||
unless @jekyll.data.present?
|
unless jekyll.data.present?
|
||||||
@jekyll.reader.read_data
|
run_in_path do
|
||||||
|
jekyll.reader.read_data
|
||||||
# Define los valores por defecto según la llave buscada
|
jekyll.data['layouts'] ||= {}
|
||||||
@jekyll.data.default_proc = proc do |data, key|
|
|
||||||
data[key] = case key
|
|
||||||
when 'layout' then {}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@jekyll.data
|
jekyll.data
|
||||||
end
|
end
|
||||||
|
|
||||||
# Traer las colecciones. Todos los artículos van a estar dentro de
|
# Traer las colecciones. Todos los artículos van a estar dentro de
|
||||||
# colecciones.
|
# colecciones.
|
||||||
def collections
|
def collections
|
||||||
unless @read
|
unless @read
|
||||||
@jekyll.reader.read_collections
|
run_in_path do
|
||||||
|
jekyll.reader.read_collections
|
||||||
|
end
|
||||||
|
|
||||||
@read = true
|
@read = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@jekyll.collections
|
jekyll.collections
|
||||||
end
|
end
|
||||||
|
|
||||||
# Traer la configuración de forma modificable
|
# Traer la configuración de forma modificable
|
||||||
|
@ -290,7 +286,9 @@ class Site < ApplicationRecord
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def theme_layouts
|
def theme_layouts
|
||||||
@jekyll.reader.read_layouts
|
run_in_path do
|
||||||
|
jekyll.reader.read_layouts
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Trae todos los valores disponibles para un campo
|
# Trae todos los valores disponibles para un campo
|
||||||
|
@ -332,6 +330,12 @@ class Site < ApplicationRecord
|
||||||
status == 'building'
|
status == 'building'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def jekyll
|
||||||
|
run_in_path do
|
||||||
|
@jekyll ||= Jekyll::Site.new(configuration)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Cargar el sitio Jekyll
|
# Cargar el sitio Jekyll
|
||||||
#
|
#
|
||||||
# TODO: En lugar de leer todo junto de una vez, extraer la carga de
|
# TODO: En lugar de leer todo junto de una vez, extraer la carga de
|
||||||
|
@ -345,10 +349,7 @@ class Site < ApplicationRecord
|
||||||
|
|
||||||
def reload_jekyll!
|
def reload_jekyll!
|
||||||
reset
|
reset
|
||||||
|
jekyll
|
||||||
Dir.chdir(path) do
|
|
||||||
@jekyll = Jekyll::Site.new(configuration)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def reload
|
def reload
|
||||||
|
@ -526,4 +527,8 @@ class Site < ApplicationRecord
|
||||||
errors.add(:design_id,
|
errors.add(:design_id,
|
||||||
I18n.t('activerecord.errors.models.site.attributes.design_id.layout_incompatible.error'))
|
I18n.t('activerecord.errors.models.site.attributes.design_id.layout_incompatible.error'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run_in_path(&block)
|
||||||
|
Dir.chdir path, &block
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
3
app/views/posts/attribute_ro/_float.haml
Normal file
3
app/views/posts/attribute_ro/_float.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th= post_label_t(attribute, post: post)
|
||||||
|
%td{ dir: dir, lang: locale }= metadata.value
|
3
app/views/posts/attribute_ro/_predefined_value.haml
Normal file
3
app/views/posts/attribute_ro/_predefined_value.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th= post_label_t(attribute, post: post)
|
||||||
|
%td{ dir: dir, lang: locale }= metadata.value
|
6
app/views/posts/attributes/_float.haml
Normal file
6
app/views/posts/attributes/_float.haml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.form-group
|
||||||
|
= label_tag "#{base}_#{attribute}", post_label_t(attribute, post: post)
|
||||||
|
= number_field base, attribute, value: metadata.value, step: metadata.step,
|
||||||
|
**field_options(attribute, metadata)
|
||||||
|
= render 'posts/attribute_feedback',
|
||||||
|
post: post, attribute: attribute, metadata: metadata
|
7
app/views/posts/attributes/_predefined_value.haml
Normal file
7
app/views/posts/attributes/_predefined_value.haml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.form-group
|
||||||
|
= label_tag "#{base}_#{attribute}", post_label_t(attribute, post: post)
|
||||||
|
= select_tag(plain_field_name_for(base, attribute),
|
||||||
|
options_for_select(metadata.values, metadata.value),
|
||||||
|
**field_options(attribute, metadata), include_blank: t('.empty'))
|
||||||
|
= render 'posts/attribute_feedback',
|
||||||
|
post: post, attribute: attribute, metadata: metadata
|
|
@ -40,7 +40,7 @@
|
||||||
%section.col
|
%section.col
|
||||||
= render 'layouts/flash'
|
= render 'layouts/flash'
|
||||||
.d-flex.justify-content-between.align-items-center.pl-2-plus.pr-2-plus.mb-2
|
.d-flex.justify-content-between.align-items-center.pl-2-plus.pr-2-plus.mb-2
|
||||||
%form
|
%form{ action: site_posts_path }
|
||||||
- @filter_params.each do |param, value|
|
- @filter_params.each do |param, value|
|
||||||
- next if param == 'q'
|
- next if param == 'q'
|
||||||
%input{ type: 'hidden', name: param, value: value }
|
%input{ type: 'hidden', name: param, value: value }
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
- if @site.locales.size > 1
|
- if @site.locales.size > 1
|
||||||
%nav#locales
|
%nav#locales
|
||||||
- @site.locales.each do |locale|
|
- @site.locales.each do |locale|
|
||||||
= link_to t("locales.#{locale}.name"), site_posts_path(@site, **@filter_params.merge(locale: locale)),
|
= link_to @site.data.dig(locale.to_s, 'locale') || locale, site_posts_path(@site, **@filter_params.merge(locale: locale)),
|
||||||
class: "mr-2 mt-2 mb-2 #{locale == @locale ? 'active font-weight-bold' : ''}"
|
class: "mr-2 mt-2 mb-2 #{locale == @locale ? 'active font-weight-bold' : ''}"
|
||||||
.pl-2-plus
|
.pl-2-plus
|
||||||
- @filter_params.each do |param, value|
|
- @filter_params.each do |param, value|
|
||||||
|
@ -72,6 +72,8 @@
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%th.border-0.background-white.position-sticky{ style: 'top: 0; z-index: 2', colspan: '4' }
|
%th.border-0.background-white.position-sticky{ style: 'top: 0; z-index: 2', colspan: '4' }
|
||||||
|
.d-flex.flex-row.justify-content-between
|
||||||
|
%div
|
||||||
= submit_tag t('posts.reorder.submit'), class: 'btn'
|
= submit_tag t('posts.reorder.submit'), class: 'btn'
|
||||||
%button.btn{ data: { action: 'reorder#unselect' } }
|
%button.btn{ data: { action: 'reorder#unselect' } }
|
||||||
= t('posts.reorder.unselect')
|
= t('posts.reorder.unselect')
|
||||||
|
@ -80,6 +82,8 @@
|
||||||
%button.btn{ data: { action: 'reorder#down' } }= t('posts.reorder.down')
|
%button.btn{ data: { action: 'reorder#down' } }= t('posts.reorder.down')
|
||||||
%button.btn{ data: { action: 'reorder#top' } }= t('posts.reorder.top')
|
%button.btn{ data: { action: 'reorder#top' } }= t('posts.reorder.top')
|
||||||
%button.btn{ data: { action: 'reorder#bottom' } }= t('posts.reorder.bottom')
|
%button.btn{ data: { action: 'reorder#bottom' } }= t('posts.reorder.bottom')
|
||||||
|
|
||||||
|
%div
|
||||||
%tbody
|
%tbody
|
||||||
- dir = t("locales.#{@locale}.dir")
|
- dir = t("locales.#{@locale}.dir")
|
||||||
- size = @posts.size
|
- size = @posts.size
|
||||||
|
@ -104,19 +108,19 @@
|
||||||
%span{ lang: post.locale, dir: dir }= post.title
|
%span{ lang: post.locale, dir: dir }= post.title
|
||||||
- if post.front_matter['draft'].present?
|
- if post.front_matter['draft'].present?
|
||||||
%span.badge.badge-primary= I18n.t('posts.attributes.draft.label')
|
%span.badge.badge-primary= I18n.t('posts.attributes.draft.label')
|
||||||
- if post.front_matter['categories'].present?
|
|
||||||
%br
|
%br
|
||||||
%small
|
%small
|
||||||
- post.front_matter['categories'].each do |category|
|
= link_to @site.layouts[post.layout].humanized_name, site_posts_path(@site, **@filter_params.merge(layout: post.layout))
|
||||||
|
- post.front_matter['categories']&.each do |category|
|
||||||
= link_to site_posts_path(@site, **@filter_params.merge(category: category)) do
|
= link_to site_posts_path(@site, **@filter_params.merge(category: category)) do
|
||||||
%span{ lang: post.locale, dir: dir }= category
|
%span{ lang: post.locale, dir: dir }= category
|
||||||
= '/' unless post.front_matter['categories'].last == category
|
= '/' unless post.front_matter['categories'].last == category
|
||||||
|
|
||||||
%td
|
%td.text-nowrap
|
||||||
= post.created_at.strftime('%F')
|
= post.created_at.strftime('%F')
|
||||||
%br/
|
%br/
|
||||||
= post.order
|
= post.order
|
||||||
%td
|
%td.text-nowrap
|
||||||
- if @usuarie || policy(post).edit?
|
- if @usuarie || policy(post).edit?
|
||||||
= link_to t('posts.edit'), edit_site_post_path(@site, post.path), class: 'btn btn-block'
|
= link_to t('posts.edit'), edit_site_post_path(@site, post.path), class: 'btn btn-block'
|
||||||
- if @usuarie || policy(post).destroy?
|
- if @usuarie || policy(post).destroy?
|
||||||
|
|
|
@ -19,8 +19,8 @@ en:
|
||||||
remember_me: 'Keeps session open for %{remember_for}'
|
remember_me: 'Keeps session open for %{remember_for}'
|
||||||
actions:
|
actions:
|
||||||
sr-help: "After this form you'll find links to recover your account and other actions."
|
sr-help: "After this form you'll find links to recover your account and other actions."
|
||||||
_true: Yes
|
_true: 'Yes'
|
||||||
_false: No
|
_false: 'No'
|
||||||
svg:
|
svg:
|
||||||
sutty:
|
sutty:
|
||||||
title: Sutty
|
title: Sutty
|
||||||
|
@ -163,7 +163,7 @@ en:
|
||||||
signature: 'With love, Sutty'
|
signature: 'With love, Sutty'
|
||||||
breadcrumb:
|
breadcrumb:
|
||||||
title: 'Your location in Sutty'
|
title: 'Your location in Sutty'
|
||||||
logout: Exit
|
logout: Log out
|
||||||
mutual_aid: Mutual aid
|
mutual_aid: Mutual aid
|
||||||
collaborations:
|
collaborations:
|
||||||
collaborate:
|
collaborate:
|
||||||
|
@ -376,6 +376,8 @@ en:
|
||||||
en: 'English'
|
en: 'English'
|
||||||
ar: 'Arabic'
|
ar: 'Arabic'
|
||||||
posts:
|
posts:
|
||||||
|
prev: Previous page
|
||||||
|
next: Next page
|
||||||
empty: "There are no results for those search parameters."
|
empty: "There are no results for those search parameters."
|
||||||
caption: Post list
|
caption: Post list
|
||||||
attribute_ro:
|
attribute_ro:
|
||||||
|
@ -413,6 +415,8 @@ en:
|
||||||
destroy: Remove image
|
destroy: Remove image
|
||||||
belongs_to:
|
belongs_to:
|
||||||
empty: "(Empty)"
|
empty: "(Empty)"
|
||||||
|
predefined_value:
|
||||||
|
empty: "(Empty)"
|
||||||
draft:
|
draft:
|
||||||
label: Draft
|
label: Draft
|
||||||
reorder:
|
reorder:
|
||||||
|
|
|
@ -19,8 +19,8 @@ es:
|
||||||
remember_me: 'Mantiene la sesión abierta por %{remember_for}'
|
remember_me: 'Mantiene la sesión abierta por %{remember_for}'
|
||||||
actions:
|
actions:
|
||||||
sr-help: 'Después del formulario encontrarás vínculos para recuperar tu cuenta, entre otras acciones.'
|
sr-help: 'Después del formulario encontrarás vínculos para recuperar tu cuenta, entre otras acciones.'
|
||||||
_true: Sí
|
_true: 'Sí'
|
||||||
_false: No
|
_false: 'No'
|
||||||
svg:
|
svg:
|
||||||
sutty:
|
sutty:
|
||||||
title: Sutty
|
title: Sutty
|
||||||
|
@ -163,7 +163,7 @@ es:
|
||||||
signature: 'Con cariño, Sutty'
|
signature: 'Con cariño, Sutty'
|
||||||
breadcrumb:
|
breadcrumb:
|
||||||
title: 'Tu ubicación en Sutty'
|
title: 'Tu ubicación en Sutty'
|
||||||
logout: Salir
|
logout: Cerrar sesión
|
||||||
mutual_aid: Ayuda mutua
|
mutual_aid: Ayuda mutua
|
||||||
collaborations:
|
collaborations:
|
||||||
collaborate:
|
collaborate:
|
||||||
|
@ -384,6 +384,8 @@ es:
|
||||||
en: 'inglés'
|
en: 'inglés'
|
||||||
ar: 'árabe'
|
ar: 'árabe'
|
||||||
posts:
|
posts:
|
||||||
|
prev: Página anterior
|
||||||
|
next: Página siguiente
|
||||||
empty: No hay artículos con estos parámetros de búsqueda.
|
empty: No hay artículos con estos parámetros de búsqueda.
|
||||||
caption: Lista de artículos
|
caption: Lista de artículos
|
||||||
attribute_ro:
|
attribute_ro:
|
||||||
|
@ -421,6 +423,8 @@ es:
|
||||||
destroy: 'Eliminar imagen'
|
destroy: 'Eliminar imagen'
|
||||||
belongs_to:
|
belongs_to:
|
||||||
empty: "(Vacío)"
|
empty: "(Vacío)"
|
||||||
|
predefined_value:
|
||||||
|
empty: "(Vacío)"
|
||||||
draft:
|
draft:
|
||||||
label: Borrador
|
label: Borrador
|
||||||
reorder:
|
reorder:
|
||||||
|
|
|
@ -57,9 +57,10 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
# Gestionar artículos según idioma
|
# Gestionar artículos según idioma
|
||||||
nested do
|
nested do
|
||||||
scope '(:locale)' do
|
scope '/(:locale)', constraint: /[a-z]{2}/ do
|
||||||
post :'posts/reorder', to: 'posts#reorder'
|
post :'posts/reorder', to: 'posts#reorder'
|
||||||
resources :posts do
|
resources :posts do
|
||||||
|
get 'p/:page', action: :index, on: :collection
|
||||||
get :preview, to: 'posts#preview'
|
get :preview, to: 'posts#preview'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
10
db/migrate/20210926205448_add_uniqueness.rb
Normal file
10
db/migrate/20210926205448_add_uniqueness.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Agrega índices únicos que pensábamos que ya existían.
|
||||||
|
class AddUniqueness < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_index :designs, :name, unique: true
|
||||||
|
add_index :designs, :gem, unique: true
|
||||||
|
add_index :licencias, :name, unique: true
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue