diff options
-rw-r--r-- | app/controllers/blog/posts_controller.rb | 13 | ||||
-rw-r--r-- | app/models/blog_post.rb | 3 | ||||
-rw-r--r-- | app/views/admin/blog/posts/_form.html.erb | 6 | ||||
-rw-r--r-- | app/views/blog/posts/archive.html.erb | 3 | ||||
-rw-r--r-- | app/views/blog/posts/index.html.erb | 1 | ||||
-rw-r--r-- | app/views/blog/posts/show.html.erb | 1 | ||||
-rw-r--r-- | app/views/blog/posts/tagged.html.erb | 22 | ||||
-rw-r--r-- | app/views/blog/shared/_post.html.erb | 10 | ||||
-rw-r--r-- | app/views/blog/shared/_tags.html.erb | 8 | ||||
-rw-r--r-- | changelog.md | 3 | ||||
-rw-r--r-- | config/locales/en.yml | 5 | ||||
-rw-r--r-- | config/locales/zh-CN.yml | 128 | ||||
-rw-r--r-- | config/routes.rb | 1 | ||||
-rw-r--r-- | db/migrate/3_acts_as_taggable_on_migration.rb | 28 | ||||
-rw-r--r-- | features/support/factories/blog_posts.rb | 1 | ||||
-rw-r--r-- | features/support/step_definitions/tags_steps.rb | 11 | ||||
-rw-r--r-- | features/tags.feature | 26 | ||||
-rw-r--r-- | lib/refinerycms-blog.rb | 2 | ||||
-rw-r--r-- | refinerycms-blog.gemspec | 5 | ||||
-rw-r--r-- | spec/models/blog_posts_spec.rb | 39 |
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 “#{@tag_name.titleize}”".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 |