aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/blog/posts_controller.rb13
-rw-r--r--app/models/blog_post.rb3
-rw-r--r--app/views/admin/blog/posts/_form.html.erb6
-rw-r--r--app/views/blog/posts/archive.html.erb3
-rw-r--r--app/views/blog/posts/index.html.erb1
-rw-r--r--app/views/blog/posts/show.html.erb1
-rw-r--r--app/views/blog/posts/tagged.html.erb22
-rw-r--r--app/views/blog/shared/_post.html.erb10
-rw-r--r--app/views/blog/shared/_tags.html.erb8
-rw-r--r--changelog.md3
-rw-r--r--config/locales/en.yml5
-rw-r--r--config/locales/zh-CN.yml128
-rw-r--r--config/routes.rb1
-rw-r--r--db/migrate/3_acts_as_taggable_on_migration.rb28
-rw-r--r--features/support/factories/blog_posts.rb1
-rw-r--r--features/support/step_definitions/tags_steps.rb11
-rw-r--r--features/tags.feature26
-rw-r--r--lib/refinerycms-blog.rb2
-rw-r--r--refinerycms-blog.gemspec5
-rw-r--r--spec/models/blog_posts_spec.rb39
20 files changed, 292 insertions, 24 deletions
diff --git a/app/controllers/blog/posts_controller.rb b/app/controllers/blog/posts_controller.rb
index 576073e..9c413ed 100644
--- a/app/controllers/blog/posts_controller.rb
+++ b/app/controllers/blog/posts_controller.rb
@@ -2,6 +2,7 @@ class Blog::PostsController < BlogController
before_filter :find_all_blog_posts, :except => [:archive]
before_filter :find_blog_post, :only => [:show, :comment, :update_nav]
+ before_filter :find_tags
respond_to :html, :js, :rss
@@ -64,6 +65,14 @@ class Blog::PostsController < BlogController
end
respond_with (@blog_posts)
end
+
+ def tagged
+ @tag_name = params[:tag_name]
+ @blog_posts = BlogPost.tagged_with(@tag_name.titleize).paginate({
+ :page => params[:page],
+ :per_page => RefinerySetting.find_or_set(:blog_posts_per_page, 10)
+ })
+ end
protected
@@ -83,5 +92,9 @@ protected
:per_page => RefinerySetting.find_or_set(:blog_posts_per_page, 10)
})
end
+
+ def find_tags
+ @tags = BlogPost.tag_counts_on(:tags)
+ end
end
diff --git a/app/models/blog_post.rb b/app/models/blog_post.rb
index 1132c8f..db85a70 100644
--- a/app/models/blog_post.rb
+++ b/app/models/blog_post.rb
@@ -1,3 +1,5 @@
+require 'acts-as-taggable-on'
+
class BlogPost < ActiveRecord::Base
default_scope :order => 'published_at DESC'
@@ -6,6 +8,7 @@ class BlogPost < ActiveRecord::Base
belongs_to :author, :class_name => 'User', :foreign_key => :user_id
has_many :comments, :class_name => 'BlogComment', :dependent => :destroy
+ acts_as_taggable
has_many :categorizations
has_many :categories, :through => :categorizations, :source => :blog_category
diff --git a/app/views/admin/blog/posts/_form.html.erb b/app/views/admin/blog/posts/_form.html.erb
index 0dc6e9b..3c0a351 100644
--- a/app/views/admin/blog/posts/_form.html.erb
+++ b/app/views/admin/blog/posts/_form.html.erb
@@ -14,6 +14,12 @@
<%= f.label :body -%>
<%= f.text_area :body, :rows => 20, :class => 'wymeditor widest' -%>
</div>
+
+ <div class='field'>
+ <%= f.label :tag_list, "Tags" -%>
+ <%= f.text_field :tag_list, :class => 'larger' -%>
+ </div>
+
<div id='more_options_field'>
<p>
<%= link_to t('.advanced_options'), "#",
diff --git a/app/views/blog/posts/archive.html.erb b/app/views/blog/posts/archive.html.erb
index d44aa7f..a2044e8 100644
--- a/app/views/blog/posts/archive.html.erb
+++ b/app/views/blog/posts/archive.html.erb
@@ -1,5 +1,4 @@
<% content_for :body_content_left do %>
- <%= @page[Page.default_parts.first.to_sym] %>
<h1><%= t('.blog_archive_for', :date => @archive_date.strftime('%B %Y')) %></h1>
<% if @blog_posts.any? %>
<section id="blog_posts">
@@ -11,8 +10,8 @@
<% end %>
<% content_for :body_content_right do %>
- <%= @page[Page.default_parts.second.to_sym] %>
<%= render :partial => "/blog/shared/categories" %>
+ <%= render :partial => "/blog/shared/tags" %>
<%= render :partial => "/blog/shared/rss_feed" %>
<%= blog_archive_list %>
<% end %>
diff --git a/app/views/blog/posts/index.html.erb b/app/views/blog/posts/index.html.erb
index 08e3578..8c3801a 100644
--- a/app/views/blog/posts/index.html.erb
+++ b/app/views/blog/posts/index.html.erb
@@ -15,6 +15,7 @@
<%=raw @page[Page.default_parts.second.to_sym] if Page.default_parts.many? %>
<%= render :partial => "/blog/shared/categories" %>
+ <%= render :partial => "/blog/shared/tags" %>
<%= render :partial => "/blog/shared/rss_feed" %>
<%= blog_archive_list %>
<% end %>
diff --git a/app/views/blog/posts/show.html.erb b/app/views/blog/posts/show.html.erb
index 504db2c..92898a4 100644
--- a/app/views/blog/posts/show.html.erb
+++ b/app/views/blog/posts/show.html.erb
@@ -49,6 +49,7 @@
<% content_for :body_content_right do %>
<%= render :partial => "/blog/shared/categories" %>
+ <%= render :partial => "/blog/shared/tags" %>
<%= render :partial => "/blog/shared/posts" %>
<%= render :partial => "/blog/shared/rss_feed" %>
<%= blog_archive_list %>
diff --git a/app/views/blog/posts/tagged.html.erb b/app/views/blog/posts/tagged.html.erb
new file mode 100644
index 0000000..29de791
--- /dev/null
+++ b/app/views/blog/posts/tagged.html.erb
@@ -0,0 +1,22 @@
+<% content_for :body_content_title, "Posts tagged &#8220;#{@tag_name.titleize}&#8221;".html_safe -%>
+
+<% content_for :body_content_left do %>
+ <% if @blog_posts.any? %>
+ <section id="blog_posts">
+ <%= render :partial => "/blog/shared/post", :collection => @blog_posts %>
+ <%= will_paginate @blog_posts %>
+ </section>
+ <% else %>
+ <p><%= t('.no_blog_articles_yet') %></p>
+ <% end %>
+<% end %>
+
+<% content_for :body_content_right do %>
+ <%= render :partial => "/blog/shared/categories" %>
+ <%= render :partial => "/blog/shared/tags" %>
+ <%= render :partial => "/blog/shared/rss_feed" %>
+ <%= blog_archive_list %>
+<% end %>
+
+<%= render :partial => "/shared/content_page" %>
+<% content_for :stylesheets, stylesheet_link_tag('refinerycms-blog') %>
diff --git a/app/views/blog/shared/_post.html.erb b/app/views/blog/shared/_post.html.erb
index 2e92f73..716c1ad 100644
--- a/app/views/blog/shared/_post.html.erb
+++ b/app/views/blog/shared/_post.html.erb
@@ -9,9 +9,13 @@
<% if (categories = post.categories).any? %>
<aside class='filed_in'>
<%= t('filed_in', :scope => 'blog.posts.show') %>
- <% categories.each_with_index do |category, index| %>
- <%= link_to category.title, blog_category_url(category) -%><%= ',' if index < ((categories.length) - 1) %>
- <% end %>
+ <%=raw categories.collect { |category| link_to category.title, blog_category_url(category) }.to_sentence %>
+ </aside>
+ <% end %>
+ <% if (tags = post.tag_list).any? %>
+ <aside class='tagged'>
+ <%= t('tagged', :scope => 'blog.posts.show') %>
+ <%=raw tags.collect { |tag| link_to tag, tagged_posts_path(tag.parameterize) }.to_sentence %>
</aside>
<% end %>
</details>
diff --git a/app/views/blog/shared/_tags.html.erb b/app/views/blog/shared/_tags.html.erb
new file mode 100644
index 0000000..f8833f1
--- /dev/null
+++ b/app/views/blog/shared/_tags.html.erb
@@ -0,0 +1,8 @@
+<% unless @tags.nil? %>
+ <h2><%= t('.title') %></h2>
+ <nav id='tags'>
+ <% tag_cloud(@tags, %w(tag1 tag2 tag3 tag4)) do |tag, css_class| %>
+ <%= link_to tag.name, tagged_posts_path(tag.name.parameterize), :class => css_class %>
+ <% end %>
+ </nav>
+<% end %> \ No newline at end of file
diff --git a/changelog.md b/changelog.md
index c5ef614..2de48d8 100644
--- a/changelog.md
+++ b/changelog.md
@@ -2,6 +2,9 @@
* Spanish language fixes [scambra](https://github.com/scambra)
* Bug fixes [scambra](https://github.com/scambra)
+* Tags [joemsak](https://github.com/joemsak)
+* Tagged posts route / view [joemsak](https://github.com/joemsak)
+* Tag cloud in sidebar
* [See full list](https://github.com/resolve/refinerycms-blog/compare/1.3...1.4)
## 1.3 [03 March 2011]
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 357f4be..f5b5461 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -101,6 +101,8 @@ en:
singular: comment
none: no comments
archives: Archives
+ tags:
+ title: "Tags"
categories:
show:
no_posts: There are no posts here yet.
@@ -122,7 +124,10 @@ en:
add: Make a Comment
other: Other Blog Posts
filed_in: Filed in
+ tagged: Tagged
submit: Send comment
+ tagged:
+ no_blog_articles_yet: There are no blog articles posted yet. Stay tuned.
archive:
blog_archive_for: 'Blog Archive for %{date}'
no_blog_articles_posted: 'There are no blog articles posted for %{date}. Stay tuned.'
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
new file mode 100644
index 0000000..a3cafe5
--- /dev/null
+++ b/config/locales/zh-CN.yml
@@ -0,0 +1,128 @@
+zh-CN:
+ plugins:
+ refinerycms_blog:
+ title: 博客
+ admin:
+ blog:
+ categories:
+ category:
+ edit: 编辑此类别
+ delete: 永久删除此类别
+ index:
+ no_items_yet: '没有此类别。 点击 "%{create}" 添加第一次类别。'
+ comments:
+ approved: '评论来自 "%{author}" 已被审批。'
+ comment:
+ view_live_html: '查看此评论 <br/><em>(opens in a new window)</em>'
+ read: 阅读此评论
+ reject: 驳回此评论
+ approve: 批准此评论
+ rejected: '评论来自 "%{author}" 已被驳回。'
+ index:
+ no_items_yet: '没有 %{type} 评论。'
+ show:
+ comment: 评论
+ blog_post: 发博
+ from: 发布由
+ date: 发布在
+ message: 评论
+ details: 详情
+ age: 年龄
+ actions: 行动
+ back: 返回至所有评论
+ reject: 驳回此评论
+ approve: 批准此评论
+ posts:
+ form:
+ advanced_options: 高级选项
+ toggle_advanced_options: 点击进入标签详解设置和菜单选项
+ save_as_draft: 保存为草稿
+ published_at: 发布日期
+ index:
+ no_items_yet: '目前尚未发博。 点击 "%{create}" 添加您的第一篇博文。'
+ uncategorized:
+ no_items_yet: '没有未归类的博文。'
+ post:
+ view_live_html: '查看此博 <br/><em>(opens in a new window)</em>'
+ edit: 编辑此博
+ delete: 永久删除此博
+ settings:
+ notification_recipients:
+ value: 发送通知
+ explanation: '每次有人发表评论,发送邮件告知有新评论。'
+ hint: '增加新评论时,将会发送邮件告知您。'
+ example: "输入您的邮件地址,如: jack@work.com, jill@office.com"
+ updated: '通知收件人已被设为 "%{recipients}"'
+ submenu:
+ categories:
+ title: 分类
+ manage: 管理
+ new: 创建新的类别
+ comments:
+ title: 评论
+ title_with_count: '评论 (%{new_count} new)'
+ new: 新
+ unmoderated: 新
+ approved: 批准
+ rejected: 驳回
+ posts:
+ title: 博文
+ manage: 管理博文
+ new: 创建新博文
+ uncategorized: 未归类博文
+ settings:
+ title: 设置
+ moderation: 等待审核
+ update_notified: 更新获得通知的人
+ comments: 评论
+ blog:
+ comment_mailer:
+ notification:
+ greeting: 您好
+ you_recieved_new_comment: 您刚收到来自网站的一条新评论
+ comment_starts: --- 评论开始 ---
+ comment_ends: --- 评论结束 ---
+ from: 来自
+ email: 邮件
+ message: 信息
+ closing_line: 亲切问候
+ ps: 'P.S. All your comments are stored in the "Blog" section of Refinery under the "Comments" submenu should you ever want to view it later there.'
+ shared:
+ categories:
+ title: 分类
+ rss_feed:
+ title: RSS源
+ subscribe: 订阅
+ posts:
+ other: 其他博文
+ created_at: '发表于 %{when}'
+ read_more: 阅读更多
+ comments:
+ singular: 评论
+ none: 没有评论
+ archives: 档案
+ categories:
+ show:
+ no_posts: 此处没有文章。
+ posts:
+ post:
+ filed_in: 用户体验
+ comment: 评论
+ comments:
+ by: '发布由 %{who}'
+ time_ago: '%{time} 之前'
+ thank_you: '感谢您的评论。'
+ thank_you_moderated: '感谢您的评论。 您的信息已被列入等待审核队列,并会在短期内出现。'
+ index:
+ no_blog_articles_yet: 尚未发布文章。敬请关注。
+ show:
+ blog_home: 博客首页
+ comments:
+ title: 评论
+ add: 发表评论
+ other: 其他博文
+ filed_in: 用户体验
+ submit: 发送评论
+ archive:
+ blog_archive_for: '博客存档 %{date}'
+ no_blog_articles_posted: '没有发布文章 %{date}。敬请关注。'
diff --git a/config/routes.rb b/config/routes.rb
index e37987a..421e845 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -6,6 +6,7 @@ Refinery::Application.routes.draw do
match 'categories/:id', :to => 'categories#show', :as => 'blog_category'
match ':id/comments', :to => 'posts#comment', :as => 'blog_post_blog_comments'
get 'archive/:year(/:month)', :to => 'posts#archive', :as => 'archive_blog_posts'
+ get 'tagged/:tag_name' => 'posts#tagged', :as => 'tagged_posts'
end
scope(:path => 'refinery', :as => 'admin', :module => 'admin') do
diff --git a/db/migrate/3_acts_as_taggable_on_migration.rb b/db/migrate/3_acts_as_taggable_on_migration.rb
new file mode 100644
index 0000000..1661061
--- /dev/null
+++ b/db/migrate/3_acts_as_taggable_on_migration.rb
@@ -0,0 +1,28 @@
+class ActsAsTaggableOnMigration < ActiveRecord::Migration
+ def self.up
+ create_table :tags do |t|
+ t.string :name
+ end
+
+ create_table :taggings do |t|
+ t.references :tag
+
+ # You should make sure that the column created is
+ # long enough to store the required class names.
+ t.references :taggable, :polymorphic => true
+ t.references :tagger, :polymorphic => true
+
+ t.string :context
+
+ t.datetime :created_at
+ end
+
+ add_index :taggings, :tag_id
+ add_index :taggings, [:taggable_id, :taggable_type, :context]
+ end
+
+ def self.down
+ drop_table :taggings
+ drop_table :tags
+ end
+end
diff --git a/features/support/factories/blog_posts.rb b/features/support/factories/blog_posts.rb
index 24436b8..3eecf53 100644
--- a/features/support/factories/blog_posts.rb
+++ b/features/support/factories/blog_posts.rb
@@ -2,5 +2,6 @@ Factory.define(:post, :class => BlogPost) do |f|
f.sequence(:title) { |n| "Top #{n} Shopping Centers in Chicago" }
f.body "These are the top ten shopping centers in Chicago. You're going to read a long blog post about them. Come to peace with it."
f.draft false
+ f.tag_list "chicago, shopping, fun times"
f.published_at Time.now
end
diff --git a/features/support/step_definitions/tags_steps.rb b/features/support/step_definitions/tags_steps.rb
new file mode 100644
index 0000000..5d4dced
--- /dev/null
+++ b/features/support/step_definitions/tags_steps.rb
@@ -0,0 +1,11 @@
+Given /^there is a blog post titled "([^"]*)" and tagged "([^"]*)"$/ do |title, tag_name|
+ @blog_post = Factory(:post, :title => title, :tag_list => tag_name)
+end
+
+When /^I visit the tagged posts page for "([^"]*)"$/ do |tag_name|
+ visit tagged_posts_path(tag_name.parameterize)
+end
+
+Then /^the blog post should have the tags "([^"]*)"$/ do |tag_list|
+ BlogPost.last.tag_list == tag_list.split(', ')
+end
diff --git a/features/tags.feature b/features/tags.feature
new file mode 100644
index 0000000..07c73cd
--- /dev/null
+++ b/features/tags.feature
@@ -0,0 +1,26 @@
+@blog_tags
+Feature: Blog Post Tags
+ Blog posts can be assigned tags
+
+ Background:
+ Given I am a logged in refinery user
+
+ Scenario: The blog post new/edit form has tag_list
+ When I am on the new blog post form
+ Then I should see "Tags"
+
+ Scenario: The blog post new/edit form saves tag_list
+ When I am on the new blog post form
+ And I fill in "Title" with "This is my blog post"
+ And I fill in "Body" with "And I love it"
+ And I fill in "Tags" with "chicago, bikes, beers, babes"
+ And I press "Save"
+
+ Then there should be 1 blog post
+ And the blog post should have the tags "chicago, bikes, beers, babes"
+
+ Scenario: The blog has a "tagged" route & view
+ Given there is a blog post titled "I love my city" and tagged "chicago"
+ When I visit the tagged posts page for "chicago"
+ Then I should see "Chicago"
+ And I should see "I love my city" \ No newline at end of file
diff --git a/lib/refinerycms-blog.rb b/lib/refinerycms-blog.rb
index 7b29cea..0158e0b 100644
--- a/lib/refinerycms-blog.rb
+++ b/lib/refinerycms-blog.rb
@@ -38,7 +38,7 @@ module Refinery
class << self
def version
- %q{1.3.1}
+ %q{1.3.2}
end
end
end
diff --git a/refinerycms-blog.gemspec b/refinerycms-blog.gemspec
index dbb96a8..42ba28d 100644
--- a/refinerycms-blog.gemspec
+++ b/refinerycms-blog.gemspec
@@ -1,8 +1,8 @@
Gem::Specification.new do |s|
s.name = %q{refinerycms-blog}
- s.version = %q{1.3.1}
+ s.version = %q{1.3.2}
s.description = %q{A really straightforward open source Ruby on Rails blog engine designed for integration with RefineryCMS.}
- s.date = %q{2011-03-04}
+ s.date = %q{2011-03-09}
s.summary = %q{Ruby on Rails blogging engine for RefineryCMS.}
s.email = %q{info@refinerycms.com}
s.homepage = %q{http://refinerycms.com}
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
s.add_dependency 'refinerycms', '>= 0.9.8'
s.add_dependency 'filters_spam', '~> 0.2'
+ s.add_dependency 'acts-as-taggable-on', '~> 2.0.6'
s.files = %w(
app
diff --git a/spec/models/blog_posts_spec.rb b/spec/models/blog_posts_spec.rb
index ef1cbf8..1b96ece 100644
--- a/spec/models/blog_posts_spec.rb
+++ b/spec/models/blog_posts_spec.rb
@@ -17,7 +17,7 @@ describe BlogPost do
end
it "requires body" do
- BlogPost.new(@attr.merge(:body => "")).should_not be_valid
+ BlogPost.new(@attr.merge(:body => nil)).should_not be_valid
end
end
@@ -47,16 +47,23 @@ describe BlogPost do
end
end
+ describe "tags" do
+ it "acts as taggable" do
+ (post = Factory(:post)).should respond_to(:tag_list)
+ post.tag_list.should include("chicago")
+ end
+ end
+
describe "authors" do
it "are authored" do
- BlogPost.instance_methods.map(&:to_sym).include? :author
+ BlogPost.instance_methods.map(&:to_sym).should include(:author)
end
end
describe "by_archive scope" do
it "returns all posts from specified month" do
- blog_post1 = Factory(:post, :published_at => Time.now - 2.minutes)
- blog_post2 = Factory(:post, :published_at => Time.now - 1.minute)
+ blog_post1 = Factory(:post, :published_at => Time.now.advance(:minutes => -2))
+ blog_post2 = Factory(:post, :published_at => Time.now.advance(:minutes => -1))
Factory(:post, :published_at => Time.now - 2.months)
date = "#{Time.now.month}/#{Time.now.year}"
BlogPost.by_archive(Time.parse(date)).count.should == 2
@@ -66,8 +73,8 @@ describe BlogPost do
describe "all_previous scope" do
it "returns all posts from previous months" do
- blog_post1 = Factory(:post, :published_at => Time.now - 1.month)
- blog_post2 = Factory(:post, :published_at => Time.now - 1.month)
+ blog_post1 = Factory(:post, :published_at => Time.now.advance(:months => -2))
+ blog_post2 = Factory(:post, :published_at => Time.now.advance(:months => -1))
Factory(:post, :published_at => Time.now)
BlogPost.all_previous.count.should == 2
BlogPost.all_previous.should == [blog_post2, blog_post1]
@@ -76,8 +83,8 @@ describe BlogPost do
describe "live scope" do
it "returns all posts which aren't in draft and pub date isn't in future" do
- blog_post1 = Factory(:post, :published_at => Time.now - 2.minutes)
- blog_post2 = Factory(:post, :published_at => Time.now - 1.minute)
+ blog_post1 = Factory(:post, :published_at => Time.now.advance(:minutes => -2))
+ blog_post2 = Factory(:post, :published_at => Time.now.advance(:minutes => -1))
Factory(:post, :draft => true)
Factory(:post, :published_at => Time.now + 1.minute)
BlogPost.live.count.should == 2
@@ -87,16 +94,16 @@ describe BlogPost do
describe "next scope" do
it "returns next article based on given article" do
- blog_post1 = Factory(:post)
- blog_post2 = Factory(:post, :published_at => Time.now + 1.minute)
+ blog_post1 = Factory(:post, :published_at => Time.now.advance(:minutes => -1))
+ blog_post2 = Factory(:post)
BlogPost.next(blog_post1).should == [blog_post2]
end
end
describe "previous scope" do
it "returns previous article based on given article" do
- blog_post1 = Factory(:post)
- blog_post2 = Factory(:post, :published_at => Time.now + 1.minute)
+ blog_post1 = Factory(:post, :published_at => Time.now.advance(:minutes => -1))
+ blog_post2 = Factory(:post)
BlogPost.previous(blog_post2).should == [blog_post1]
end
end
@@ -123,14 +130,14 @@ describe BlogPost do
end
it "returns false if post pub date is in future" do
- Factory(:post, :published_at => Time.now + 1.minute).live?.should be_false
+ Factory(:post, :published_at => Time.now.advance(:minutes => 1)).live?.should be_false
end
end
describe "#next" do
it "returns next article when called on current article" do
- Factory(:post)
- blog_post = Factory(:post, :published_at => Time.now + 1.minute)
+ Factory(:post, :published_at => Time.now.advance(:minutes => -1))
+ blog_post = Factory(:post)
blog_posts = BlogPost.all
blog_posts.last.next.should == blog_post
end
@@ -139,7 +146,7 @@ describe BlogPost do
describe "#prev" do
it "returns previous article when called on current article" do
Factory(:post)
- blog_post = Factory(:post, :published_at => Time.now - 1.minute)
+ blog_post = Factory(:post, :published_at => Time.now.advance(:minutes => -1))
blog_posts = BlogPost.all
blog_posts.first.prev.should == blog_post
end