mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-23 00:46:23 +00:00
relación de muchos a muchos artículos
This commit is contained in:
parent
a078f2b87e
commit
ec02a45002
4 changed files with 116 additions and 3 deletions
84
app/models/metadata_has_and_belongs_to_many.rb
Normal file
84
app/models/metadata_has_and_belongs_to_many.rb
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Establece una relación de muchos a muchos artículos. Cada campo es un
|
||||
# Array de UUID que se mantienen sincronizados.
|
||||
#
|
||||
# Por ejemplo:
|
||||
#
|
||||
# Un libro puede tener muches autores y une autore muchos libros. La
|
||||
# relación has_many tiene que traer todes les autores relacionades con
|
||||
# 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
|
||||
|
||||
# Mantiene la relación inversa si existe.
|
||||
#
|
||||
# La relación belongs_to se mantiene actualizada en la modificación
|
||||
# actual. Lo que buscamos es mantener sincronizada esa relación.
|
||||
#
|
||||
# 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
|
||||
self[:value] = sanitize value
|
||||
|
||||
return true unless inverse? && !included?
|
||||
|
||||
(belonged_to - belongs_to).each do |p|
|
||||
p[inverse].value.delete post.uuid.value
|
||||
end
|
||||
|
||||
(belongs_to - belonged_to).each do |p|
|
||||
p[inverse].value << post.uuid.value
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def sanitize(sanitizable)
|
||||
sanitizable.map do |v|
|
||||
super v
|
||||
end
|
||||
end
|
||||
|
||||
def post_exists?
|
||||
!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?
|
||||
end
|
||||
end
|
|
@ -121,9 +121,10 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
|
|||
MetadataTemplate::RELATED_METHODS.each do |m|
|
||||
next unless post[a].respond_to? m
|
||||
|
||||
p = post[a].public_send(m)
|
||||
|
||||
files << p.path.absolute if p.save(validate: false)
|
||||
# La respuesta puede ser una PostRelation también
|
||||
[post[a].public_send(m)].flatten.compact.each do |p|
|
||||
files << p.path.absolute if p.save(validate: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -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)
|
22
app/views/posts/attributes/_has_and_belongs_to_many.haml
Normal file
22
app/views/posts/attributes/_has_and_belongs_to_many.haml
Normal 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 }
|
Loading…
Reference in a new issue