From c5cd07a82ef83f3532b538eb9ffac3f4fd888b39 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 11 Feb 2021 16:44:36 -0300 Subject: [PATCH] =?UTF-8?q?revisi=C3=B3n=20de=20habtm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/metadata_belongs_to.rb | 6 +- .../metadata_has_and_belongs_to_many.rb | 75 +++++-------------- app/models/metadata_has_many.rb | 12 +++ .../attributes/_has_and_belongs_to_many.haml | 1 + config/locales/en.yml | 2 + config/locales/es.yml | 2 + 6 files changed, 38 insertions(+), 60 deletions(-) diff --git a/app/models/metadata_belongs_to.rb b/app/models/metadata_belongs_to.rb index 0f43fce..27c50f9 100644 --- a/app/models/metadata_belongs_to.rb +++ b/app/models/metadata_belongs_to.rb @@ -23,7 +23,7 @@ class MetadataBelongsTo < MetadataRelatedPosts def validate super - errors << I18n.t('metadata.belongs_to.missing_post') if value.present? && !post_exists? + errors << I18n.t('metadata.belongs_to.missing_post') unless post_exists? errors.empty? end @@ -59,7 +59,7 @@ class MetadataBelongsTo < MetadataRelatedPosts # El campo que es la relación inversa de este def inverse - layout.metadata.dig name, 'inverse' + @inverse ||= layout.metadata.dig(name, 'inverse')&.to_sym end # El Post relacionado con este artículo @@ -90,7 +90,7 @@ class MetadataBelongsTo < MetadataRelatedPosts private def post_exists? - posts.find(value, uuid: true).present? + value.present? && belongs_to.nil? end def sanitize(uuid) diff --git a/app/models/metadata_has_and_belongs_to_many.rb b/app/models/metadata_has_and_belongs_to_many.rb index e08c991..f14827e 100644 --- a/app/models/metadata_has_and_belongs_to_many.rb +++ b/app/models/metadata_has_and_belongs_to_many.rb @@ -10,40 +10,7 @@ # el libro actual. La relación belongs_to tiene que traer todes les # autores que tienen este libro. La relación es bidireccional, no hay # diferencia entre has_many y belongs_to. -class MetadataHasAndBelongsToMany < MetadataBelongsTo - def default_value - [] - end - - # Posts a los que pertenece. Memoizamos por value para obtener - # siempre la última relación. - # - # Buscamos todos los Post contenidos en el valor actual. No - # garantizamos el orden. - # - # @return [PostRelation] Posts - def belongs_to - @belongs_to ||= {} - @belongs_to[value.hash.to_s] ||= posts.where(uuid: value) - end - - # Devuelve la lista de Posts relacionados con este buscándolos en la - # relación inversa. #save debería mantenerlos sincronizados. - # - # @return [PostRelation] - def has_many - @has_many ||= {} - @has_many[value.hash.to_s] ||= posts.where(inverse.to_sym => post.uuid.value) - end - alias had_many has_many - - # Posts a los que pertenecía - # - # @return [PostRelation] Posts - def belonged_to - @belonged_to ||= posts.where(uuid: document.data.fetch(name.to_s, [])) - end - +class MetadataHasAndBelongsToMany < MetadataHasMany # Mantiene la relación inversa si existe. # # La relación belongs_to se mantiene actualizada en la modificación @@ -52,39 +19,33 @@ class MetadataHasAndBelongsToMany < MetadataBelongsTo # Buscamos en belongs_to la relación local, si se eliminó hay que # quitarla de la relación remota, sino hay que agregarla. def save - return true unless changed? - + # XXX: No usamos super self[:value] = sanitize value - return true unless inverse? && !included? + return true unless changed? + return true unless inverse? - (belonged_to - belongs_to).each do |p| - p[inverse].value.delete post.uuid.value + (had_many - has_many).each do |remove| + remove[inverse]&.value&.delete post.uuid.value end - (belongs_to - belonged_to).each do |p| - p[inverse].value << post.uuid.value + (has_many - had_many).each do |add| + next unless add[inverse] + next if add[inverse].value.include? post.uuid.value + + add[inverse].value << post.uuid.value end true end - def sanitize(sanitizable) - sanitizable.map do |v| - super v - end - end + private - def post_exists? - return true if empty? && can_be_empty? - - !belongs_to.empty? - end - - # Todos los artículos relacionados incluyen a este? - def included? - belongs_to.map do |p| - p[inverse].value.include? post.uuid.value - end.all? + # Igual que en MetadataRelatedPosts + # TODO: Mover a un módulo + def sanitize(uuid) + super(uuid.map do |u| + u.to_s.gsub(/[^a-f0-9\-]/i, '') + end) end end diff --git a/app/models/metadata_has_many.rb b/app/models/metadata_has_many.rb index 978bc4a..ec79ddb 100644 --- a/app/models/metadata_has_many.rb +++ b/app/models/metadata_has_many.rb @@ -14,6 +14,14 @@ class MetadataHasMany < MetadataRelatedPosts super(new_value) end + def validate + super + + errors << I18n.t('metadata.has_many.missing_posts') unless posts_exist? + + errors.empty? + end + # Todos los Post relacionados def has_many @has_many ||= posts.where(uuid: value) @@ -63,4 +71,8 @@ class MetadataHasMany < MetadataRelatedPosts def related_methods @related_methods ||= %i[has_many had_many].freeze end + + def posts_exist? + has_many.size == value.size + end end diff --git a/app/views/posts/attributes/_has_and_belongs_to_many.haml b/app/views/posts/attributes/_has_and_belongs_to_many.haml index d39d124..e36b655 100644 --- a/app/views/posts/attributes/_has_and_belongs_to_many.haml +++ b/app/views/posts/attributes/_has_and_belongs_to_many.haml @@ -1,5 +1,6 @@ .form-group = label_tag "#{base}_#{attribute}", post_label_t(attribute, post: post) + = hidden_field_tag "#{base}[#{attribute}][]", '' .mapable{ dir: dir, lang: locale, data: { values: metadata.value.to_json, diff --git a/config/locales/en.yml b/config/locales/en.yml index 1535a62..9e8cc57 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -48,6 +48,8 @@ en: end_in_the_past: "Event end can't happen before the start" belongs_to: missing_post: "Couldn't find the related post" + has_many: + missing_posts: "Couldn't find some related posts" exceptions: post: site_missing: 'Needs an instance of Site' diff --git a/config/locales/es.yml b/config/locales/es.yml index 8ec1527..0bf0368 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -48,6 +48,8 @@ es: end_in_the_past: 'El fin del evento no puede ser anterior al comienzo' belongs_to: missing_post: 'No se pudo encontrar el artículo relacionado' + has_many: + missing_posts: 'No se pudieron encontrar algunos artículos relacionados' exceptions: post: site_missing: 'Necesita una instancia de Site'