diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 9a017a29..dea9dc90 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -17,18 +17,27 @@ class PostsController < ApplicationController def update p = post_params + @site = find_site + @post = find_post(@site) # crear un array a partir de una cadena separada por comas [:tags,:categories].each do |comma| p[comma] = p.dig(comma).split(',').map(&:strip) end - binding.pry + @post.update_attributes(p) + if @post.save + redirect_to site_post_path(@site, @post) + else + render 'posts/edit' + end end private + # Solo permitir cambiar estos atributos de cada articulo def post_params - params.require(:post).permit(:title, :date, :tags, :categories, :content) + params.require(:post).permit(:title, :date, :tags, + :categories, :content, :slug) end end diff --git a/app/models/post.rb b/app/models/post.rb index 39b8cf4c..d2f46c21 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -12,7 +12,10 @@ class Post # Trabajar con posts. Si estamos creando uno nuevo, el **site** y # el **front_matter** son necesarios, sino, **site** y **post**. # XXX chequear que se den las condiciones - def initialize(site:, post:, front_matter: {}) + def initialize(site:, post: nil, front_matter: {}) + raise ArgumentError, I18n.t('posts.errors.site') unless site.is_a?(Site) + raise ArgumentError, I18n.t('posts.errors.post') unless post.is_a?(Jekyll::Document) + @site = site @post = post # los errores tienen que ser un hash para que @@ -20,7 +23,8 @@ class Post @errors = {} @front_matter = front_matter - new_post! unless @post + # Crea un post nuevo si no especificamos el post + new_post unless @post load_data! unless new? end @@ -61,7 +65,7 @@ class Post alias :category :categories def path - @post.try :path || File.join(@site.path, '_posts', basename_from_front_matter) + basename_changed? ? File.join(@site.path, '_posts', basename_from_front_matter) : @post.try(:path) end def id @@ -79,23 +83,39 @@ class Post end def content - @post.content + @content ||= @post.content + end + + # imita Model.update_attributes de ActiveRecord + def update_attributes(attrs) + attrs.each_pair do |k,i| + # el contenido no es metadata + if k == 'content' + @content = i + else + set_metadata k.to_sym, i + end + end end private def new_post - opts = { site: @site, collection: @site.posts } - @post = ::Jekyll::Document.new(path, opts) - @site.posts.docs << @post - @site.posts.docs.sort! + opts = { site: @site, collection: @site.jekyll.posts } + @post = Jekyll::Document.new(path, opts) + @site.jekyll.posts.docs << @post + @site.jekyll.posts.docs.sort! @post end # Obtiene metadatos def get_metadata(name) - new? ? @front_matter.dig(name) : @post.data[name] + @front_matter.key?(name) ? @front_matter.dig(name) : @post.data[name] + end + + def set_metadata(name, value) + @front_matter[name] = value end # Cambiar el nombre del archivo si cambió el título o la fecha. @@ -105,7 +125,7 @@ class Post return true unless basename_changed? if File.exist? path - @errors << 'El archivo destino ya existe' + add_error path: I18n.t('posts.errors.path') return end @@ -114,7 +134,7 @@ class Post end def replace_post!(path) - @site.posts.docs.delete @post + @site.jekyll.posts.docs.delete @post new_post end @@ -122,18 +142,22 @@ class Post # Obtiene el nombre del archivo a partir de los datos que le # pasemos def basename_from_front_matter - date = @front_matter[:date].strftime('%F') - title = ::Jekyll::Utils.slugify(@front_matter[:title]) - ext = @post.try :ext || 'markdown' + _date = @front_matter[:date] + date = _date.respond_to?(:strftime) ? _date.strftime('%F') : _date + title = get_metadata 'slug' || Jekyll::Utils.slugify(@front_matter[:title]) + ext = get_metadata 'ext' || '.markdown' - "#{date}-#{title}.#{ext}" + "#{date}-#{title}#{ext}" end # Toma los datos del front matter local y los mueve a los datos # que van a ir al post. Si hay símbolos se convierten a cadenas, - # porque Jekyll trabaja con cadenas. + # porque Jekyll trabaja con cadenas. Se excluyen otros datos que no + # van en el frontmatter def merge_data_with_front_matter! - @data.merge! Hash[@front_matter.map { |k, v| [k.to_s, v] }] + @data.merge! Hash[@front_matter.map do |k, v| + [k.to_s, v] unless REJECT_FROM_DATA.include? k + end.compact] end # Carga una copia de los datos del post original excluyendo datos @@ -169,11 +193,23 @@ class Post return true if r.zero? - @errors << 'No se pudo escribir el archivo' + add_error file: I18n.t('posts.errors.file') false end def full_content "#{@data.to_yaml}---\n\n#{@content}" end + + def add_error(hash) + hash.each_pair do |k,i| + if @errors.key?(k) + @errors[k] = [@errors[k], i] + else + @errors[k] = i + end + end + + @errors + end end diff --git a/app/models/site.rb b/app/models/site.rb index 4c6d17fb..80712145 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -3,9 +3,11 @@ class Site attr_accessor :jekyll + attr_reader :path - def initialize(jekyll:) + def initialize(jekyll:, path: nil) @jekyll = jekyll + @path = path || @jekyll.config['source'] end # Obtener el nombre del sitio @@ -24,12 +26,16 @@ class Site def posts return @posts if @posts - @jekyll.read if @jekyll.posts.docs.empty? + if @jekyll.posts.docs.empty? + @jekyll.read + # Queremos saber cuantas veces releemos los articulos + Rails.logger.info 'Leyendo articulos' + end # Los convertimos a una clase intermedia capaz de acceder a sus # datos y modificarlos @posts = @jekyll.posts.docs.map do |post| - Post.new(site: @jekyll, post: post) + Post.new(site: self, post: post) end end @@ -69,7 +75,7 @@ class Site config[unneeded] = [] if config.key? unneeded end - Site.new(jekyll: ::Jekyll::Site.new(config)) + Site.new(jekyll: ::Jekyll::Site.new(config), path: j) end end.compact end diff --git a/app/views/posts/_form.haml b/app/views/posts/_form.haml index ad9468f0..68d4c9f5 100644 --- a/app/views/posts/_form.haml +++ b/app/views/posts/_form.haml @@ -1,3 +1,9 @@ +- unless @post.errors.empty? + .alert.alert-danger + %ul + - @post.errors.each do |error| + %li= error + = form_tag site_post_path(@site, @post), method: :patch, class: 'form' do .form-group = submit_tag t('posts.save'), class: 'btn btn-success' @@ -22,3 +28,8 @@ = text_field 'post', 'tags', value: @post.tags.join(', '), class: 'form-control' %small.text-muted.form-text= t('posts.tags_help') + .form-group + = label_tag 'post_slug', t('posts.slug') + = text_field 'post', 'slug', value: @post.slug, + class: 'form-control' + %small.text-muted.form-text= t('posts.slug_help') diff --git a/config/locales/en.yml b/config/locales/en.yml index f2713112..1e7c2544 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -17,3 +17,10 @@ en: tags_help: 'Comma separated!' categories: 'Categories' categories_help: 'Comma separated!' + slug: 'Slug' + slug_help: 'This is the name of the article on the URL, ie. /title/. You can leave it empty.' + errors: + site: 'Argument `site` must be of class Site' + post: 'Argument `post` must be of class Post' + path: 'File already exist' + file: "Couldn't write the file" diff --git a/config/locales/es.yml b/config/locales/es.yml index 07ca386a..d7a13396 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -15,3 +15,8 @@ es: title: 'Título' categories: 'Categorías' categories_help: '¡Separadas por comas!' + slug: 'Nombre la URL' + slug_help: 'Esto es el nombre del artículo en la URL, por ejemplo /título/. Puedes dejarlo vacío.' + errors: + path: 'El archivo destino ya existe' + file: 'No se pudo escribir el archivo'