relacion de uno a muchos

This commit is contained in:
f 2020-07-22 20:35:43 -03:00
parent ec02a45002
commit 52d26918b5
6 changed files with 118 additions and 12 deletions

View file

@ -73,6 +73,14 @@ class MetadataBelongsTo < MetadataRelatedPosts
@belonged_to ||= posts.find(document.data[name.to_s], uuid: true)
end
def related_posts?
true
end
def related_methods
@related_methods ||= %i[belongs_to belonged_to].freeze
end
private
def sanitize(uuid)

View file

@ -0,0 +1,71 @@
# frozen_string_literal: true
# La diferencia con MetadataRelatedPosts es que la relación también
# actualiza los Posts remotos.
#
# Localmente tenemos un Array de UUIDs. Remotamente tenemos una String
# apuntando a un Post, que se mantiene actualizado como el actual.
class MetadataHasMany < MetadataRelatedPosts
# Todos los Post relacionados según la relación remota
def has_many_remote
@has_many_remote ||= posts.where(inverse => post.uuid.value)
end
# Todos los Post relacionados
def has_many
@has_many ||= {}
@has_many[value.hash.to_s] ||= posts.where(uuid: value)
end
# La relación anterior
def had_many
return [] if document.data[name.to_s].blank?
@had_many ||= posts.where(uuid: document.data[name.to_s])
end
def inverse?
inverse.present?
end
# La relación inversa
#
# @return [Nil,Symbol]
def inverse
layout.metadata.dig(name, 'inverse')&.to_sym
end
# Actualizar las relaciones inversas. Hay que buscar la diferencia
# entre had y has_many.
def save
self[:value] = sanitize value
return true unless inverse?
(had_many - has_many).each do |remove|
remove[inverse].value = remove[inverse].default_value
end
(has_many - had_many).each do |add|
add[inverse].value = post.uuid.value
end
true
end
def related_posts?
true
end
def related_methods
@related_methods ||= %i[has_many had_many].freeze
end
private
def sanitize(sanitizable)
sanitizable.map do |uuid|
uuid.gsub(/[^a-f0-9\-]/, '')
end
end
end

View file

@ -10,14 +10,6 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
:layout, keyword_init: true) do
include ActionText::ContentHelper
# Métodos que tienen artículos relacionados
#
# Ver el final del archivo.
#
# XXX: Por alguna razón no se pueden definir constantes en un Struct
#
# RELATED_METHODS = %i[]
# El valor por defecto
def default_value
raise NotImplementedError
@ -85,6 +77,14 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
true
end
def related_posts?
false
end
def related_methods
raise NotImplementedError
end
private
# Si es obligatorio no puede estar vacío
@ -106,6 +106,3 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
end
end
# rubocop:enable Metrics/BlockLength
# Definir la constante después de definir el Struct.
MetadataTemplate.const_set 'RELATED_METHODS', %i[belongs_to belonged_to].freeze

View file

@ -118,7 +118,9 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
files = [post.path.absolute]
post.attributes.each do |a|
MetadataTemplate::RELATED_METHODS.each do |m|
next unless post[a].related_posts?
post[a].related_methods.each do |m|
next unless post[a].respond_to? m
# La respuesta puede ser una PostRelation también

View file

@ -0,0 +1,6 @@
%tr{ id: attribute }
%th= post_label_t(attribute, post: post)
%td
%ul{ dir: dir, lang: locale }
- metadata.has_many.each do |p|
%li= link_to p.title.value, site_post_path(site, p.id)

View file

@ -0,0 +1,22 @@
.form-group
= label_tag "post_#{attribute}", post_label_t(attribute, post: post)
.mapable{ dir: dir, lang: locale,
data: { values: metadata.value.to_json,
'default-values': metadata.values.to_json,
name: "post[#{attribute}][]", list: id_for_datalist(attribute),
remove: 'false', legend: post_label_t(attribute, post: post),
button: t('posts.attributes.add'),
described: id_for_help(attribute) } }
= text_field(*field_name_for('post', attribute, '[]'),
value: metadata.value.join(', '),
dir: dir, lang: locale,
**field_options(attribute, metadata))
= render 'posts/attribute_feedback',
post: post, attribute: attribute, metadata: metadata
%datalist{ id: id_for_datalist(attribute) }
- metadata.values.keys.each do |value|
%option{ value: value }