From 1bcb91b6ec457c9984ba15b759b8c7bd89e1106c Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Jun 2018 18:34:33 -0300 Subject: [PATCH] empezar a mover la logica de plantillas a su propio modelo --- app/models/post.rb | 80 ++-------------------- app/models/post/template_field.rb | 109 ++++++++++++++++++++++++++++++ app/views/posts/_form.haml | 10 +-- doc/plantillas.md | 30 ++++++++ 4 files changed, 150 insertions(+), 79 deletions(-) create mode 100644 app/models/post/template_field.rb diff --git a/app/models/post.rb b/app/models/post.rb index 7e98c99e..97075290 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -224,88 +224,20 @@ class Post def template_fields return [] unless template - @template_fields ||= template.front_matter.reject do |key, _| - REJECT_FROM_TEMPLATE.include? key - end.keys + @template_fields ||= template.front_matter.map do |key, contents| + next if REJECT_FROM_TEMPLATE.include? key + + Post::TemplateField.new(self, key, contents) + end.compact end # devuelve las plantillas como strong params def template_params @template_params ||= template_fields.map do |k| - v = template.get_front_matter(k) - if v.is_a? Array - { k.to_sym => [] } - else - k.to_sym - end + k.to_param end end - # Obtiene el tipo de campo para la plantilla - def template_form_type_for(field) - return if (tt = template.get_front_matter(field)).nil? - - case - when tt == 'string' - type = 'text' - when tt == 'text' - type = 'text_area' - when tt.is_a?(String) && tt.split('/', 2).count == 2 - type = 'select' - when tt.is_a?(Array) - type = 'select' - when tt.is_a?(FalseClass) || tt.is_a?(TrueClass) - type = 'check_box' - end - - type - end - - def template_multiple_values?(field) - template.get_front_matter(field).is_a? Array - end - - # Obtiene los valores posibles para el campo de la plantilla - def template_values_for(field) - return '' if %w[string text].include? template.get_front_matter(field) - - # Para obtener los valores posibles, hay que procesar la string y - # convertirla a parametros - # - # XXX Prestar atención a no enviar metodos privados - - value = template.get_front_matter(field) - - # Si es una array de un solo elemento, es un indicador de que - # tenemos que rellenarla con los valores que indica - if value.is_a?(Array) && value.count == 1 - values = value.first - else - values = value - end - - # Procesar el valor - if values.is_a?(String) - value = values.split(':', 2).map do |v| - collection, attr = v.split('/', 2) - - if collection == 'site' - # TODO puede ser peligroso permitir acceder a cualquier - # atributo de site? No estamos trayendo nada fuera de - # lo normal - @site.send(attr.to_sym) - else - @site.everything_of(attr, lang: collection) - end - end - - value = value.last.zip value.first - end - - # En última instancia, traer el valor por defecto - value - end - def template @template ||= template_from_layout end diff --git a/app/models/post/template_field.rb b/app/models/post/template_field.rb new file mode 100644 index 00000000..4f5abc3d --- /dev/null +++ b/app/models/post/template_field.rb @@ -0,0 +1,109 @@ +# Representa los distintos tipos de campos que pueden venir de una +# plantilla compleja +class Post + class TemplateField + attr_reader :post, :contents, :key + + def initialize(post, key, contents) + @post = post + @key = key + @contents = contents + end + + def type + return @type if @type + return unless simple? + + case + when contents == 'string' + @type = 'text' + when contents == 'text' + @type = 'text_area' + when contents.is_a?(String) && contents.split('/', 2).count == 2 + @type = 'select' + when contents.is_a?(Array) + @type = 'select' + when contents.is_a?(FalseClass) || contents.is_a?(TrueClass) + @type = 'check_box' + end + + @type + end + + # Si la plantilla es simple no está admitiendo Hashes como valores + def simple? + !complex? + end + + def complex? + contents.is_a? Hash + end + + # XXX Retrocompatibilidad + def to_s + key + end + + def to_param + if array? + { key.to_sym => [] } + else + key.to_sym + end + end + + def array? + @contents.is_a? Array + end + + # TODO detectar cuando es complejo y tomar el valor de :multiple + def multiple? + array? + end + + def value + @contents + end + + # Obtiene los valores posibles para el campo de la plantilla + def values + return '' if %w[string text].include? value + + # Para obtener los valores posibles, hay que procesar la string y + # convertirla a parametros + # + # XXX Prestar atención a no enviar metodos privados + + # Si es una array de un solo elemento, es un indicador de que + # tenemos que rellenarla con los valores que indica + if value.is_a?(Array) && value.count == 1 + values = value.first + else + values = value + end + + # Procesar el valor + if values.is_a?(String) + value = values.split(':', 2).map do |v| + collection, attr = v.split('/', 2) + + if collection == 'site' + # TODO puede ser peligroso permitir acceder a cualquier + # atributo de site? No estamos trayendo nada fuera de + # lo normal + post.site.send(attr.to_sym) + else + post.site.everything_of(attr, lang: collection) + end + end + + value = value.last.zip value.first + end + + # En última instancia, traer el valor por defecto + value + + end + + end +end diff --git a/app/views/posts/_form.haml b/app/views/posts/_form.haml index f2792d91..fcb58944 100644 --- a/app/views/posts/_form.haml +++ b/app/views/posts/_form.haml @@ -76,11 +76,11 @@ { class: 'form-control select2' } %small.text-muted.form-text= t('posts.lang_help') - @post.template_fields.each do |template| - - next unless type = @post.template_form_type_for(template) + - next unless type = template.type .form-group - = label_tag "post_#{template}", template.humanize + = label_tag "post_#{template}", template.to_s.humanize - name = "post[#{template}]" - - value = @post.new? ? @post.template_values_for(template) : @post.get_front_matter(template) + - value = @post.new? ? template.values : @post.get_front_matter(template) - case type - when 'text' = text_field 'post', template, @@ -92,8 +92,8 @@ = hidden_field 'post', template, value: 'false' = check_box_tag name, 'true', value == 'true', class: 'form-control' - when 'select' - = select_tag name, options_for_select(@post.template_values_for(template), @post.get_front_matter(template)), + = select_tag name, options_for_select(template.values, @post.get_front_matter(template)), { class: 'form-control select2', - multiple: @post.template_multiple_values?(template) } + multiple: template.multiple? } .form-group = submit_tag t('posts.save'), class: 'btn btn-success' diff --git a/doc/plantillas.md b/doc/plantillas.md index 3ad9356e..073289ac 100644 --- a/doc/plantillas.md +++ b/doc/plantillas.md @@ -178,3 +178,33 @@ collections: TODO: agregarlo especificamente en `app/models/site.rb` al cargar el sitio. + +## Plantillas complejas + +Algunas plantillas necesitan comportamientos más complejos, por ejemplo +cuando un campo es requerido o no es público. + +``` +campo: + help: "Un texto de ayuda" + public: false + required: true + value: {bool,string,text,array,url,email} + min: 0 + max: 100 + multiple: false +``` + +Ahora los `value` pueden estar anidados, es decir que dentro de cada +value puede haber una serie de `campo` con los mismos valores. + +Las plantillas más simples asumen ciertos valores por defecto: + +``` +help: nil +public: true +required: false +min: nil +max: nil +multiple: true +```