-
-
Save metaskills/11071934 to your computer and use it in GitHub Desktop.
| # In lib/tasks/blog.rake | |
| namespace :blog do | |
| desc "Generate a new blog post with a title. Ex: rake blog:post['My New Post']" | |
| task :post, [:title] => [:environment] do |t, args| | |
| date = Time.now.strftime("%G-%m-%d") | |
| title = args[:title].to_s.strip | |
| if title.blank? | |
| fail 'Please supply a title.' | |
| else | |
| slug = title.split(' ').map{ |s| s.downcase }.join('-') | |
| file = Rails.root.join 'app', 'views', 'blog', "#{date}-#{slug}.md" | |
| File.open(file,'w') { |f| f.write("---\ntitle: #{title}\n---\n\n\n") } | |
| end | |
| end | |
| end |
| # In app/controllers/blog_controller.rb | |
| class BlogController < ApplicationController | |
| layout 'site' | |
| before_filter :find_post, only: [:show] | |
| def index | |
| @posts = BlogPost.all | |
| end | |
| def show | |
| if stale?(@post, public: true) | |
| render text: @post.html, layout: 'site' | |
| end | |
| end | |
| private | |
| def find_post | |
| @post = BlogPost.find params[:id] | |
| redirect_to blog_index_path unless @post | |
| end | |
| end |
| # In app/models/blog_post.rb | |
| class BlogPost | |
| include ActionView::Helpers::TextHelper | |
| attr_reader :slug | |
| class << self | |
| def all | |
| all_slugs.map{ |slug| new(slug) }.sort | |
| end | |
| def find(slug) | |
| all.detect { |post| post.slug == slug } | |
| end | |
| def first | |
| all.first | |
| end | |
| def exists?(slug) | |
| all_slugs.include?(slug) | |
| end | |
| def directory | |
| Rails.root.join 'app', 'views', 'blog' | |
| end | |
| private | |
| def all_slugs | |
| @all_slugs ||= Dir.glob("#{directory}/*.md").map { |f| File.basename(f).sub(/\.md$/,'') } | |
| end | |
| end | |
| def initialize(slug) | |
| @slug = slug | |
| @data = {} | |
| parse_file | |
| end | |
| def title | |
| @data['title'] || slug.sub(/\d{4}-\d{2}-\d{2}-/, '').tap do |t| | |
| t.replace t.titleize | |
| t.sub! /Homemarks/, 'HomeMarks' | |
| end | |
| end | |
| def date | |
| Date.parse(slug) | |
| end | |
| def date_formatted | |
| day_format = ActiveSupport::Inflector.ordinalize(date.day) | |
| date.strftime "%B #{day_format}, %G" | |
| end | |
| def html | |
| Rails.cache.fetch("#{cache_key}/html") { to_html } | |
| end | |
| def excerpt | |
| first_ptag = Nokogiri::HTML(html).css('p:first').text.squish | |
| truncate strip_tags(first_ptag), length: 200, separator: ' ' | |
| end | |
| def path | |
| "/blog/#{slug}" | |
| end | |
| def permalink | |
| "/blog/#{slug}" | |
| end | |
| def inspect | |
| "<#{self.class.name} date: #{date.iso8601}, title: #{title.inspect}, slug: #{slug.inspect}>" | |
| end | |
| def == other | |
| self.inspect == other.inspect | |
| end | |
| alias :eql? :== | |
| def <=> other | |
| other.date <=> date | |
| end | |
| def updated_at | |
| File.mtime(file_path) | |
| end | |
| def cache_key | |
| ActiveSupport::Cache.expand_cache_key ['blog', slug, updated_at.to_i] | |
| end | |
| private | |
| def parse_file | |
| @markdown = Tilt::ErubisTemplate.new do | |
| fdata = file_data | |
| if fdata =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m | |
| @data = SafeYAML.load($1) | |
| $POSTMATCH | |
| else | |
| fdata | |
| end | |
| end.render(scope, post: self) | |
| end | |
| def file_path | |
| self.class.directory.join "#{slug}.md" | |
| end | |
| def file_data | |
| Rails.cache.fetch("#{cache_key}/markdown") { File.read(file_path) } | |
| end | |
| def markdown | |
| @markdown | |
| end | |
| def to_html | |
| Jekyll::Converters::Markdown::RedcarpetParser.new({ | |
| 'highlighter' => 'rouge', | |
| 'redcarpet' => { | |
| 'extensions' => ["no_intra_emphasis", "fenced_code_blocks", "autolink", "strikethrough", "lax_spacing", "superscript", "with_toc_data"] | |
| } | |
| }).convert(markdown) | |
| end | |
| def scope | |
| ApplicationController.helpers.clone.tap do |h| | |
| h.singleton_class.send :include, Rails.application.routes.url_helpers | |
| end | |
| end | |
| end |
| gem 'jekyll', '~> 2.0.0.alpha', github: 'jekyll/jekyll' | |
| gem 'nokogiri' | |
| gem 'redcarpet' | |
| gem 'rouge' |
| # config/routes.rb | |
| resources :blog, only: [:index, :show] |
In blog_post model:
attr_reader :slug, :data
I'm getting an error when I go to http://localhost:3000/blog
Missing template blog/index, application/index with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee]}. Searched in: * "/Users/acandael/Sites/mysite/app/views"
in my views/blog folder I created an .md file called '2014-04-24-my-first-post.md'
what does the directive layout 'site' in blog_controller.rb mean?
ok, when I go to http://localhost:3000/blog/2014-04-24.md I got the blogpost rendering. The only issue I have now, is that no css is rendered. When I look in the page source, I see that the page source is missing the header section.
Added examples of a BlogHelper and a site layout to show how I got headers, comments, etc in too.
what does the directive layout 'site' in blog_controller.rb mean?
@acandael That is just my example layout. Your's may be "application".
Thanks @felixbuenemann
Thanks for this @metaskills . Could you list a few of the other dependencies in the gemfile, such as Rails and Ruby versions?
Beware that this gist uses %G for the year when formatting dates, but %G is a weird thing that displays the week year, not the current year, so it'll give the wrong result for a few days each year (as described here). (What's the week year? It's the year that most of the current week is in. If it's Monday on December 31, you're in a a week that is mostly in the next year, so it'll return the next year, not the current year.) It's a strange, hard-to-detect bug. The solution is to use %Y rather than %G.
File.basename has a second param to strip the file ending, no need for sub.