active_blog 0.0.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +11 -1
- data/app/assets/javascripts/active_blog/active_admin.js +23 -0
- data/app/assets/stylesheets/active_blog/active_admin.css.scss +21 -0
- data/app/assets/stylesheets/active_blog/application.css +2 -1
- data/app/assets/stylesheets/active_blog/blog_posts.css +8 -0
- data/app/controllers/active_blog/blog_posts_controller.rb +33 -2
- data/app/helpers/active_blog/application_helper.rb +27 -4
- data/app/helpers/active_blog/blog_posts_helper.rb +27 -1
- data/app/models/active_blog/blog_post.rb +30 -38
- data/app/views/active_blog/active_admin/_blog_post_form.html.erb +16 -0
- data/app/views/active_blog/active_admin/_blog_post_show.html.erb +18 -0
- data/app/views/active_blog/active_admin/_show.html.erb +2 -0
- data/app/views/active_blog/blog_posts/_blog_post.html.erb +32 -0
- data/app/views/active_blog/blog_posts/_blog_post_schema.html.erb +5 -0
- data/app/views/active_blog/blog_posts/_sidebar.html.erb +11 -0
- data/app/views/active_blog/blog_posts/archives.html.erb +12 -0
- data/app/views/active_blog/blog_posts/atom.xml.builder +21 -0
- data/app/views/active_blog/blog_posts/index.html.erb +18 -13
- data/app/views/active_blog/blog_posts/preview.js.erb +1 -0
- data/app/views/active_blog/blog_posts/show.html.erb +7 -10
- data/db/migrate/20111116040223_create_active_blog_blog_posts.rb +3 -2
- data/lib/active_blog/ext/string.rb +39 -0
- data/lib/active_blog/mapper.rb +13 -2
- data/lib/active_blog/version.rb +1 -1
- data/lib/active_blog.rb +25 -4
- data/lib/generators/active_blog/install/install_generator.rb +4 -0
- data/lib/generators/active_blog/install/templates/README +17 -0
- data/lib/generators/active_blog/install/templates/active_blog.rb +18 -3
- data/lib/generators/active_blog/install/templates/blog_posts.rb +3 -8
- data/test/dummy/config/application.rb +1 -0
- data/test/dummy/config/routes.rb +2 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +5 -1
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +74 -0
- data/test/dummy/log/test.log +1252 -0
- data/test/functional/active_blog/blog_posts_controller_test.rb +9 -9
- data/test/functional/active_blog/routing_test.rb +25 -0
- data/test/unit/active_blog/blog_post_test.rb +32 -3
- data/test/unit/active_blog/sample_renderer_test.rb +22 -0
- metadata +40 -14
data/README.markdown
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# ActiveBlog is a work in progress.
|
2
2
|
|
3
|
-
ActiveBlog is Rails engine written to satisfy blogging requirements.
|
3
|
+
ActiveBlog is Rails engine written to satisfy *minimal* blogging requirements.
|
4
4
|
|
5
5
|
The ActiveBlog BlogPost model:
|
6
6
|
|
@@ -38,6 +38,8 @@ Run the generator
|
|
38
38
|
|
39
39
|
./script/rails generate active_blog:install
|
40
40
|
|
41
|
+
[Follow the installer's directions](https://github.com/mchung/active_blog/blob/master/lib/generators/active_blog/install/templates/README)
|
42
|
+
|
41
43
|
Install the migrations
|
42
44
|
|
43
45
|
rake db:migrate
|
@@ -49,3 +51,11 @@ Start your server with `foreman` or `rails s` and visit your new blog located at
|
|
49
51
|
To create a new blog post, visit the admin area located at:
|
50
52
|
|
51
53
|
http://localhost:5000/admin/active_blog_blog_posts
|
54
|
+
|
55
|
+
|
56
|
+
# TODO
|
57
|
+
|
58
|
+
* The ActiveAdmin BlogPost form should show realtime Markdown updates
|
59
|
+
* The ActiveAdmin BlogPost form should allow users to upload content to S3
|
60
|
+
* Tests
|
61
|
+
* Document Parent App Hooks (content_for :sidebar, content_for :title, content_for: head)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
$(document).ready(function() {
|
2
|
+
var $form = $('form.active_blog_blog_post');
|
3
|
+
|
4
|
+
$("#button-preview").bind("ajax:before", function() {
|
5
|
+
var action = $form.attr('action');
|
6
|
+
$form.attr('action', '/blog/-/preview');
|
7
|
+
$form.submit();
|
8
|
+
$form.attr('action', action);
|
9
|
+
return false;
|
10
|
+
});
|
11
|
+
|
12
|
+
$form.bind('submit', function() {
|
13
|
+
if ($form.attr('action') === '/blog/-/preview') {
|
14
|
+
console.log("In post " + this.action);
|
15
|
+
$.post(this.action, $(this).serialize(), null, "script");
|
16
|
+
return false;
|
17
|
+
}
|
18
|
+
});
|
19
|
+
|
20
|
+
// $("#new_active_blog_blog_post").live('keyup', function() {
|
21
|
+
// $("#button-preview").trigger('click');
|
22
|
+
// });
|
23
|
+
});
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#main_content {
|
2
|
+
margin: 0 auto;
|
3
|
+
#main_form, .panel.show.blog {
|
4
|
+
float: left;
|
5
|
+
width: 49%;
|
6
|
+
}
|
7
|
+
#live_preview, .buffer {
|
8
|
+
float: right;
|
9
|
+
width: 49%;
|
10
|
+
background-color: #efefef;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
.panel {
|
15
|
+
h4 {
|
16
|
+
span {
|
17
|
+
font-size: 90%;
|
18
|
+
font-weight: bold;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
@@ -3,5 +3,6 @@
|
|
3
3
|
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
4
4
|
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
5
5
|
*= require_self
|
6
|
-
*=
|
6
|
+
*= require 'active_blog/active_admin'
|
7
|
+
*= require 'active_blog/blog_posts'
|
7
8
|
*/
|
@@ -1,11 +1,42 @@
|
|
1
1
|
module ActiveBlog
|
2
2
|
class BlogPostsController < ApplicationController
|
3
|
+
|
4
|
+
before_filter :only => [:index, :show, :archives] do
|
5
|
+
@recent_blog_posts = BlogPost.live.recent
|
6
|
+
end
|
7
|
+
|
3
8
|
def index
|
4
|
-
@blog_posts = BlogPost.live.
|
9
|
+
@blog_posts = BlogPost.live.page(params[:page])
|
10
|
+
end
|
11
|
+
|
12
|
+
def archives
|
13
|
+
@blog_posts = BlogPost.all
|
5
14
|
end
|
6
|
-
|
15
|
+
|
7
16
|
def show
|
8
17
|
@blog_post = BlogPost.live.where(:cached_slug => params[:cached_slug]).first
|
18
|
+
if @blog_post
|
19
|
+
render
|
20
|
+
else
|
21
|
+
# TODO(mc): Should 404
|
22
|
+
redirect_to active_blog_path, :notice => "No blog post with that URL"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def preview
|
27
|
+
@blog_post = BlogPost.new(params[:active_blog_blog_post])
|
28
|
+
@blog_post_partial = render_to_string(:partial => 'active_blog/active_admin/blog_post_show')
|
29
|
+
|
30
|
+
respond_to do |format|
|
31
|
+
format.js
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def atom
|
36
|
+
@blog_posts = BlogPost.live.order('published_at DESC').limit(10)
|
37
|
+
respond_to do |format|
|
38
|
+
format.xml
|
39
|
+
end
|
9
40
|
end
|
10
41
|
end
|
11
42
|
end
|
@@ -1,16 +1,39 @@
|
|
1
1
|
module ActiveBlog
|
2
|
+
# These helpers are intended to be used by developers.
|
3
|
+
#
|
4
|
+
#
|
2
5
|
module ApplicationHelper
|
3
|
-
def
|
4
|
-
ActiveBlog.
|
6
|
+
def active_blog_title
|
7
|
+
ActiveBlog.title
|
5
8
|
end
|
6
9
|
|
7
|
-
def
|
8
|
-
|
10
|
+
def active_blog_description
|
11
|
+
ActiveBlog.description
|
12
|
+
end
|
13
|
+
|
14
|
+
def active_blog_sidebar(&block)
|
15
|
+
sidebar_content_for = ActiveBlog.content_for_sidebar
|
9
16
|
if sidebar_content_for
|
10
17
|
content_for sidebar_content_for do
|
11
18
|
yield
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
22
|
+
|
23
|
+
def active_blog_author_name
|
24
|
+
ActiveBlog.author_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def active_blog_author_uri
|
28
|
+
ActiveBlog.author_uri
|
29
|
+
end
|
30
|
+
|
31
|
+
def active_blog_author_email
|
32
|
+
ActiveBlog.author_email
|
33
|
+
end
|
34
|
+
|
35
|
+
def active_blog_atom_link_tag
|
36
|
+
auto_discovery_link_tag(:atom, "#{active_blog_feed_url}", {:title => "Subscribe to this blog"})
|
37
|
+
end
|
15
38
|
end
|
16
39
|
end
|
@@ -1,7 +1,33 @@
|
|
1
1
|
module ActiveBlog
|
2
2
|
module BlogPostsHelper
|
3
3
|
def markdown(text)
|
4
|
-
|
4
|
+
regular = { :hard_wrap => true, :autolink => true, :space_after_headers => true }
|
5
|
+
make_markdown(regular).render(text).html_safe
|
6
|
+
end
|
7
|
+
|
8
|
+
def markdown_for_schema(text)
|
9
|
+
truncate(strip_tags(markdown(text)).strip.gsub(/\n/, ' '), :length => 250)
|
10
|
+
end
|
11
|
+
|
12
|
+
def make_markdown(opts)
|
13
|
+
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, opts)
|
14
|
+
markdown
|
15
|
+
end
|
16
|
+
|
17
|
+
def schema_date(date)
|
18
|
+
date.strftime("%Y-%m-%d")
|
19
|
+
end
|
20
|
+
|
21
|
+
def schema_span_for(name, content)
|
22
|
+
content_tag(:span, "", :itemprop => name, :content => content)
|
23
|
+
end
|
24
|
+
|
25
|
+
def blog_post_path(blog_post)
|
26
|
+
if blog_post.new_record?
|
27
|
+
admin_blog_posts_path(blog_post)
|
28
|
+
else
|
29
|
+
admin_blog_post_path(blog_post)
|
30
|
+
end
|
5
31
|
end
|
6
32
|
end
|
7
33
|
end
|
@@ -1,51 +1,43 @@
|
|
1
1
|
module ActiveBlog
|
2
2
|
class BlogPost < ActiveRecord::Base
|
3
3
|
set_table_name 'active_blog_blog_posts'
|
4
|
-
|
5
|
-
|
4
|
+
paginates_per ActiveBlog.paginates_per
|
5
|
+
default_scope :order => 'published_at DESC'
|
6
|
+
|
7
|
+
scope :live, where('published_at < ? AND draft = ?', Time.zone.now, false)
|
8
|
+
scope :recent, limit(5)
|
9
|
+
|
10
|
+
validates_presence_of :title, :allow_blank => false, :allow_nil => false, :message => "can't be blank"
|
11
|
+
validates_presence_of :body, :allow_blank => false, :allow_nil => false, :message => "can't be blank"
|
12
|
+
validates_presence_of :cached_slug, :allow_blank => false, :allow_nil => false, :message => "can't be blank"
|
13
|
+
validates_uniqueness_of :cached_slug, :message => "must be unique"
|
14
|
+
validate :title_must_not_start_with_dash
|
15
|
+
validate :title_must_not_be
|
6
16
|
before_validation :build_cached_slug
|
17
|
+
after_initialize :init
|
18
|
+
|
19
|
+
# protected methods
|
7
20
|
|
8
|
-
scope :live, where("published_at < ? AND draft = ?", Time.now, false)
|
9
21
|
def build_cached_slug
|
10
|
-
|
22
|
+
# Don't build slug if it already exists.
|
23
|
+
if self.cached_slug.nil?
|
24
|
+
self.cached_slug = title.to_slug
|
25
|
+
end
|
11
26
|
end
|
12
27
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# ==== Example
|
19
|
-
#
|
20
|
-
# "The World is Beautiful!".to_slug # => "the-world-is-beautiful"
|
21
|
-
#
|
22
|
-
# ==== Returns
|
23
|
-
# String:: A 'sluggified' version of this string
|
24
|
-
#
|
25
|
-
# --
|
26
|
-
# @api public
|
27
|
-
def to_slug(string)
|
28
|
-
# Perform transliteration to replace non-ascii characters with an ascii
|
29
|
-
# character
|
30
|
-
value = string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n, '').to_s
|
31
|
-
|
32
|
-
# Remove single quotes from input
|
33
|
-
value.gsub!(/[']+/, '')
|
34
|
-
|
35
|
-
# Replace any non-word character (\W) with a space
|
36
|
-
value.gsub!(/\W+/, ' ')
|
37
|
-
|
38
|
-
# Remove any whitespace before and after the string
|
39
|
-
value.strip!
|
40
|
-
|
41
|
-
# All characters should be downcased
|
42
|
-
value.downcase!
|
28
|
+
def title_must_not_start_with_dash
|
29
|
+
if title.starts_with?('-')
|
30
|
+
errors.add(:title, 'cannot start with a dash')
|
31
|
+
end
|
32
|
+
end
|
43
33
|
|
44
|
-
|
45
|
-
|
34
|
+
def title_must_not_be
|
35
|
+
errors.add(:title, "cannot be named 'archives'") if title == 'archives'
|
36
|
+
end
|
46
37
|
|
47
|
-
|
48
|
-
|
38
|
+
def init
|
39
|
+
# Set now as the default published_at date. Only set if currently nil
|
40
|
+
self.published_at ||= Time.zone.now
|
49
41
|
end
|
50
42
|
end
|
51
43
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<div id="main_form">
|
2
|
+
<%= semantic_form_for(@blog_post, :url => blog_post_path(@blog_post)) do |f| %>
|
3
|
+
<%= f.inputs "Write a new blog post" do %>
|
4
|
+
<%= f.input :title, :as => :string, :required => true, :hint => "A great blog post title", :input_html => { :placeholder => "A great blog post title" } %>
|
5
|
+
<%= f.input :cached_slug, :as => :string, :label => "Slug", :hint => "#{active_blog_url}/...", :input_html => { :disabled => true } %>
|
6
|
+
<%= f.input :body, :as => :text, :label => "Blog post (Markdown)", :hint => "Use Markdown"%>
|
7
|
+
<%= f.input :draft, :as => :boolean, :label => "Draft?", :hint => "Drafts are not published" %>
|
8
|
+
<%= f.input :published_at, :label => "Publication date" %>
|
9
|
+
<% end %>
|
10
|
+
<%= f.buttons do %>
|
11
|
+
<%= f.commit_button %>
|
12
|
+
<li class="cancel"><%= link_to("Preview", active_blog_preview_path, { :id => "button-preview", :remote => true, "data-type" => "script"}) %>
|
13
|
+
<% end %>
|
14
|
+
<% end %>
|
15
|
+
</div>
|
16
|
+
<div id="live_preview"></div>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<div class="panel <%= @blog_post.new_record? ? "new" : "show" %> blog">
|
2
|
+
<h3><%= @blog_post.new_record? ? "Live Preview" : "Blog Entry" %></h3>
|
3
|
+
<div>
|
4
|
+
<h4><%= @blog_post.title || "[Title]" %>
|
5
|
+
<span>
|
6
|
+
<% if @blog_post.cached_slug %>
|
7
|
+
(<%= active_blog_post_url(:cached_slug => @blog_post.cached_slug) %>)
|
8
|
+
<% end %>
|
9
|
+
</span>
|
10
|
+
</h4>
|
11
|
+
</div>
|
12
|
+
<div>
|
13
|
+
|
14
|
+
</div>
|
15
|
+
<div>
|
16
|
+
<%= markdown(@blog_post.body || "Body") %>
|
17
|
+
</div>
|
18
|
+
</div>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<%#
|
2
|
+
This partial is used by #index and #show. It behaves differently by displaying different schema
|
3
|
+
types according to the caller.
|
4
|
+
|
5
|
+
Google Rich Snippets doesn't like nested schemas in certain cases.
|
6
|
+
%>
|
7
|
+
<div class="active_blog entry" <%= show ? '' : "itemscope itemtype='http://schema.org/BlogPosting'" %>>
|
8
|
+
<%- if show %>
|
9
|
+
<%= content_for :schema do %>
|
10
|
+
<%= render :partial => 'blog_post_schema', :locals => {:blog_post => blog_post} %>
|
11
|
+
<% end %>
|
12
|
+
<% else %>
|
13
|
+
<%= render :partial => 'blog_post_schema', :locals => {:blog_post => blog_post} %>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<h6>
|
17
|
+
<%= blog_post.published_at.strftime("%B %e %G") %>
|
18
|
+
<% if blog_post.new_record? %>
|
19
|
+
<a href="" itemscope itemprop="url">∞</a>
|
20
|
+
<% else %>
|
21
|
+
<a href="<%= active_blog_post_path(blog_post.cached_slug) %>">∞</a>
|
22
|
+
<% end %>
|
23
|
+
</h6>
|
24
|
+
<h2>
|
25
|
+
<%= blog_post.title %>
|
26
|
+
</h2>
|
27
|
+
|
28
|
+
<div class="active_blog body">
|
29
|
+
<%= markdown(blog_post.body || "") %>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
<hr/>
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<%= schema_span_for 'name', "#{blog_post.title} | #{active_blog_title}" %>
|
2
|
+
<%= schema_span_for 'description', markdown_for_schema(blog_post.body) %>
|
3
|
+
<%= schema_span_for 'datePublished', schema_date(blog_post.published_at) %>
|
4
|
+
<%= schema_span_for 'headline', blog_post.title %>
|
5
|
+
<%= schema_span_for 'url', active_blog_post_url(blog_post.cached_slug) %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<%= active_blog_sidebar do %>
|
2
|
+
<div class='section active_blog sidebar'>
|
3
|
+
<h6>Recent posts</h6>
|
4
|
+
</div>
|
5
|
+
<ul class='unstyled recent'>
|
6
|
+
<% @recent_blog_posts.each do |recent_blog_post| %>
|
7
|
+
<li><a href='<%= active_blog_post_path(recent_blog_post.cached_slug) %>' title='<%= recent_blog_post.title %>'><%= recent_blog_post.title %></a></li>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
<%= link_to 'Archives', active_blog_archives_path %>
|
11
|
+
<% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= content_for :title do %><%= "#{active_blog_title} » Archives" %><% end %>
|
2
|
+
<div class="section active_blog archives">
|
3
|
+
<h1>Archives</h1>
|
4
|
+
<p>By Date</p>
|
5
|
+
<ul>
|
6
|
+
<% @blog_posts.each do |blog_post| %>
|
7
|
+
<li><%= link_to blog_post.title, active_blog_post_path(blog_post.cached_slug) %>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
</div>
|
11
|
+
|
12
|
+
<%= render :partial => 'sidebar' %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
atom_feed({}) do |feed|
|
2
|
+
feed.title(active_blog_title)
|
3
|
+
feed.updated(@blog_posts[0].published_at) if @blog_posts.length > 0
|
4
|
+
|
5
|
+
@blog_posts.each do |post|
|
6
|
+
feed.entry(post, {
|
7
|
+
:published_at => post.published_at,
|
8
|
+
:updated_at => post.updated_at,
|
9
|
+
:url => active_blog_post_url(post.cached_slug)
|
10
|
+
}) do |entry|
|
11
|
+
entry.title(post.title)
|
12
|
+
entry.content(markdown(post.body), :type => 'html')
|
13
|
+
|
14
|
+
entry.author do |author|
|
15
|
+
author.name(active_blog_author_name) if active_blog_author_name
|
16
|
+
author.uri(active_blog_author_uri) if active_blog_author_uri
|
17
|
+
author.email(active_blog_author_email) if active_blog_author_email
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,17 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
<%=
|
1
|
+
<%= content_for :title do %><%= active_blog_title %><% end %>
|
2
|
+
<%= content_for :head do %><%= active_blog_atom_link_tag %><% end %>
|
3
|
+
<%= content_for :schema do %>
|
4
|
+
<%= schema_span_for 'name', active_blog_title %>
|
5
|
+
<%= schema_span_for 'description', active_blog_description %>
|
6
|
+
<%= schema_span_for 'url', active_blog_url %>
|
5
7
|
<% end %>
|
8
|
+
<div class="section active_blog index">
|
9
|
+
<h1><%= active_blog_title %></h1>
|
6
10
|
|
7
|
-
<% @blog_posts.
|
8
|
-
|
9
|
-
|
10
|
-
<%= markdown(blog.body) %>
|
11
|
-
<hr/>
|
12
|
-
<% end %>
|
11
|
+
<% if @blog_posts.empty? %>
|
12
|
+
<%= link_to "Write your first blog post", new_admin_blog_post_path %>
|
13
|
+
<% end %>
|
13
14
|
|
15
|
+
<div itemprop="blogPosts">
|
16
|
+
<%= render :partial => "blog_post", :collection => @blog_posts, :locals => {:show => false} %>
|
17
|
+
</div>
|
14
18
|
|
15
|
-
<%=
|
16
|
-
|
17
|
-
|
19
|
+
<%= paginate @blog_posts %>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<%= render :partial => "sidebar" %>
|
@@ -0,0 +1 @@
|
|
1
|
+
$('#live_preview').html('<%= escape_javascript(@blog_post_partial.html_safe) %>');
|
@@ -1,10 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
<
|
4
|
-
<
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
<%= blog_sidebar do %>
|
9
|
-
<br/>
|
10
|
-
<% end %>
|
1
|
+
<%= content_for :title do %><%= @blog_post.title %><% end %>
|
2
|
+
<%= content_for :schema_itemtype do %>http://schema.org/BlogPosting<% end %>
|
3
|
+
<div class="section active_blog show">
|
4
|
+
<h1><%= active_blog_title %></h1>
|
5
|
+
<%= render :partial => "blog_post", :locals => {:blog_post => @blog_post, :show => true} %>
|
6
|
+
</div>
|
7
|
+
<%= render :partial => "sidebar" %>
|
@@ -2,7 +2,7 @@ class CreateActiveBlogBlogPosts < ActiveRecord::Migration
|
|
2
2
|
def change
|
3
3
|
create_table :active_blog_blog_posts do |t|
|
4
4
|
t.string :title
|
5
|
-
t.
|
5
|
+
t.text :body
|
6
6
|
t.boolean :draft
|
7
7
|
t.datetime :published_at
|
8
8
|
t.string :cached_slug
|
@@ -12,5 +12,6 @@ class CreateActiveBlogBlogPosts < ActiveRecord::Migration
|
|
12
12
|
t.timestamps
|
13
13
|
end
|
14
14
|
add_index :active_blog_blog_posts, :id
|
15
|
+
add_index :active_blog_blog_posts, :cached_slug, :unique => true
|
15
16
|
end
|
16
|
-
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class String
|
2
|
+
# Generate a slug for the string +value+.
|
3
|
+
#
|
4
|
+
# A slug should consist of numbers (0-9), lowercase letters (a-z) and
|
5
|
+
# dashes (-). Any other characters should be filtered.
|
6
|
+
#
|
7
|
+
# ==== Example
|
8
|
+
#
|
9
|
+
# "The World is Beautiful!".to_slug # => "the-world-is-beautiful"
|
10
|
+
#
|
11
|
+
# ==== Returns
|
12
|
+
# String:: A 'sluggified' version of this string
|
13
|
+
#
|
14
|
+
# --
|
15
|
+
# @api public
|
16
|
+
def to_slug
|
17
|
+
# Perform transliteration to replace non-ascii characters with an ascii
|
18
|
+
# character
|
19
|
+
value = self.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n, '').to_s
|
20
|
+
|
21
|
+
# Remove single quotes from input
|
22
|
+
value.gsub!(/[']+/, '')
|
23
|
+
|
24
|
+
# Replace any non-word character (\W) with a space
|
25
|
+
value.gsub!(/\W+/, ' ')
|
26
|
+
|
27
|
+
# Remove any whitespace before and after the string
|
28
|
+
value.strip!
|
29
|
+
|
30
|
+
# All characters should be downcased
|
31
|
+
value.downcase!
|
32
|
+
|
33
|
+
# Replace spaces with dashes
|
34
|
+
value.gsub!(' ', '-')
|
35
|
+
|
36
|
+
# Return the resulting slug
|
37
|
+
value
|
38
|
+
end
|
39
|
+
end
|
data/lib/active_blog/mapper.rb
CHANGED
@@ -5,8 +5,19 @@ module ActionDispatch::Routing
|
|
5
5
|
#
|
6
6
|
#
|
7
7
|
scope mount_location do
|
8
|
-
|
9
|
-
|
8
|
+
resources :blog_posts, :module => 'active_blog', :path => '/', :only => [] do
|
9
|
+
get 'page/:page', :action => :index, :on => :collection
|
10
|
+
# match '/', :action => :index, :on => :collection, :as => :all
|
11
|
+
# match '/-/preview', :action => :preview, :on => :collection, :as => :preview, :via => [:post, :put]
|
12
|
+
# match '/-/feed', :action => :feed, :on => :collection, :as => :feed, :via => [:get]
|
13
|
+
# match '/:cached_slug', :action => :show, :on => :collection, :as => :post, :via => [:get]
|
14
|
+
end
|
15
|
+
match '/' => 'active_blog/blog_posts#index', :as => :active_blog, :via => [:get]
|
16
|
+
match '/-/preview' => 'active_blog/blog_posts#preview', :as => :active_blog_preview, :via => [:post, :put]
|
17
|
+
match '/atom.xml' => 'active_blog/blog_posts#atom', :as => :active_blog_feed, :via => [:get], :format => :xml
|
18
|
+
match '/archives' => 'active_blog/blog_posts#archives', :as => :active_blog_archives, :via => [:get]
|
19
|
+
# Always last.
|
20
|
+
match '/:cached_slug' => 'active_blog/blog_posts#show', :as => :active_blog_post, :via => [:get]
|
10
21
|
end
|
11
22
|
end
|
12
23
|
end
|
data/lib/active_blog/version.rb
CHANGED
data/lib/active_blog.rb
CHANGED
@@ -1,16 +1,37 @@
|
|
1
1
|
require 'active_blog/engine'
|
2
2
|
require 'active_blog/mapper'
|
3
3
|
require 'redcarpet'
|
4
|
+
require 'active_blog/ext/string'
|
4
5
|
|
5
6
|
module ActiveBlog
|
6
7
|
|
7
8
|
# The blog's title
|
8
|
-
mattr_accessor :
|
9
|
-
@@
|
9
|
+
mattr_accessor :title
|
10
|
+
@@title = 'New ActiveBlog!'
|
11
|
+
|
12
|
+
# The blog's description
|
13
|
+
mattr_accessor :description
|
14
|
+
@@description = "Here's where your description goes"
|
10
15
|
|
11
16
|
# Yield to your layout's sidebar, i.e. :sidebar
|
12
|
-
mattr_accessor :
|
13
|
-
@@
|
17
|
+
mattr_accessor :content_for_sidebar
|
18
|
+
@@content_for_sidebar = nil
|
19
|
+
|
20
|
+
# Blog author's name
|
21
|
+
mattr_accessor :author_name
|
22
|
+
@@author_name = nil
|
23
|
+
|
24
|
+
# Blog author's uri
|
25
|
+
mattr_accessor :author_uri
|
26
|
+
@@author_uri = nil
|
27
|
+
|
28
|
+
# Blog author's email
|
29
|
+
mattr_accessor :author_email
|
30
|
+
@@author_email = nil
|
31
|
+
|
32
|
+
# Blog posts per page
|
33
|
+
mattr_accessor :paginates_per
|
34
|
+
@@paginates_per = 10
|
14
35
|
|
15
36
|
def self.setup
|
16
37
|
yield self
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
TO COMPLETE YOUR INSTALLATION
|
3
|
+
|
4
|
+
1. Add the following line to application.css
|
5
|
+
|
6
|
+
*= require 'active_blog/application'
|
7
|
+
|
8
|
+
2. Add the following to active_admin.css
|
9
|
+
|
10
|
+
// ActiveBlog CSS Styles
|
11
|
+
@import "active_blog/active_admin";
|
12
|
+
|
13
|
+
3. Add the following to active_admin.js
|
14
|
+
|
15
|
+
//= require active_blog/active_admin
|
16
|
+
|
17
|
+
Thanks for installing ActiveBlog!
|