Create a gist now

Instantly share code, notes, and snippets.

@metaskills /Gemfile
Last active Jun 21, 2016

What would you like to do?
# 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
# app/helpers/blog_helper.rb
module BlogHelper
def blog_post?
controller_name == 'blog' && action_name == 'show'
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 directory
Rails.root.join 'app', 'views', 'blog'
end
private
def all_slugs
@all_slugs ||= Dir.glob("#{directory}/*.md").map { |f| File.basename(f,'.md') }
end
end
def initialize(slug)
@slug = slug
@data = {}
parse_file
end
def title
@data['title'] || slug.sub(/\d{4}-\d{2}-\d{2}-/, '').titleize
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 inspect
"<#{self.class.name} date: #{date.iso8601}, title: #{title.inspect}, slug: #{slug.inspect}>"
end
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'
gem 'nokogiri'
gem 'redcarpet'
gem 'rouge'
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #000000; font-weight: bold } /* Keyword */
.highlight .o { color: #000000; font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #000000; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #000000; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #d01040 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #0086B3 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nl { color: #990000; font-weight: bold } /* Name.Label */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #000080 } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #d01040 } /* Literal.String.Backtick */
.highlight .sc { color: #d01040 } /* Literal.String.Char */
.highlight .sd { color: #d01040 } /* Literal.String.Doc */
.highlight .s2 { color: #d01040 } /* Literal.String.Double */
.highlight .se { color: #d01040 } /* Literal.String.Escape */
.highlight .sh { color: #d01040 } /* Literal.String.Heredoc */
.highlight .si { color: #d01040 } /* Literal.String.Interpol */
.highlight .sx { color: #d01040 } /* Literal.String.Other */
.highlight .sr { color: #009926 } /* Literal.String.Regex */
.highlight .s1 { color: #d01040 } /* Literal.String.Single */
.highlight .ss { color: #990073 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
# config/routes.rb
resources :blog, only: [:index, :show]
# app/views/layouts/site.html.haml
.container
= render partial: 'blog/header' if blog_post?
~ yield :layout
= render partial: 'blog/call_to_action' if blog_post?
= render partial: 'blog/comments' if blog_post? && Rails.env.production?

File.basename has a second param to strip the file ending, no need for sub.

jnillo commented Apr 24, 2014

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.

Owner

metaskills commented May 9, 2014

Added examples of a BlogHelper and a site layout to show how I got headers, comments, etc in too.

Owner

metaskills commented May 9, 2014

what does the directive layout 'site' in blog_controller.rb mean?

@acandael That is just my example layout. Your's may be "application".

Owner

metaskills commented May 9, 2014

Thanks for this @metaskills . Could you list a few of the other dependencies in the gemfile, such as Rails and Ruby versions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment