FlashObject

自从youtube横空出世之后,网上flash视频在线观看越来越流行了,flashobject插件就提供了非常方便的构建在线flash视频的功能,它是基于http://blog.deconcept.com/swfobject之上的应用。下面来看个实例:

1. 创建工程:

$rails test_flashobject_helper
$cd test_flashobject_helper

2. 安装插件:

$script/plugin install http://lipsiasoft.googlecode.com/svn/trunk/flashobject_helper

3. 生成controller,修改view页面:

$script/generate controller flashs
#app/views/layouts/application.html.erb
<%= javascript_include_tag :defaults %>
<%= javascript_include_tag "flashobject" %>


<%= @content_for_layout %>
#app/views/flashs/index.html.erb
<%= flashobject_tag "/flash/demo.swf", :size => "350x320" %>

4. 在public目录下新建flash目录,并在flash目录下放一个名为demo.swf的flash文件

5. 启动server,输入http://localhost:3000/flashs即可查看flash视频

Posted in  rails plugins


Annotate models

Rails的约定优于配置和Ruby的动态性,使得model类变得十分简洁,但是也带来了一个问题:如果你想知道一个model有哪些属性时,必须去查看数据库或者migration,这给开发带来了极大的不便。Annotate models插件很好地解决了这个问题,它在model类的起始处以注释的形式写明了所有的属性,下面来看个例子:

1. 创建工程:

$rails test_annotate_models
$cd rails test_annotate_models

2. 安装插件:

$script/plugin install http://repo.pragprog.com/svn/Public/plugins/annotate_models

3. 生成测试模型:

$script/generate model post title:string body:text
$rake db:migrate

4. 生成annotation:

$rake annotate_models

5. 效果:

# == Schema Information
# Schema version: 1
#
# Table name: posts
#
#  id         :integer         not null, primary key
#  title      :string(255)
#  body       :text
#  created_at :datetime
#  updated_at :datetime
#
class Post  ActiveRecord::Base
end

6. 增加模型:

$script/generate model comment body:text post:references
$script/generate migration add_comment_count_to_post
#db/migrate/003_add_comment_count_to_post.rb
class AddCommentCountToPost  ActiveRecord::Migration
  def self.up
    add_column :posts, :comment_count, :integer
  end

  def self.down
    remove_column :posts, :comment_count
  end
end
$rake db:migrate

7. 再试试annotation:

$rake annotate_models

8. 效果:

# == Schema Information
# Schema version: 3
#
# Table name: posts
#
#  id            :integer         not null, primary key
#  title         :string(255)
#  body          :text
#  created_at    :datetime
#  updated_at    :datetime
#  comment_count :integer
#
class Post  ActiveRecord::Base
end
# == Schema Information
# Schema version: 3
#
# Table name: comments
#
#  id         :integer         not null, primary key
#  body       :text
#  post_id    :integer
#  created_at :datetime
#  updated_at :datetime
#
class Comment  ActiveRecord::Base
end

Posted in  rails plugins


Restful Authentication

Restful Authentication提供了基于Restful形式的身份认证功能,包括email激活,登陆跳转等等功能。

1. 创建工程:

$rails test_restful_authentication
$cd test_restful_authentication

2. 安装插件:

$script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication

3. 生成测试模型和数据表:

$script/generate authenticated user sessions --include-activation
$script/generate scaffold post title:string body:text
$rake db:migrate

4. 增加routes:

#config/routes.rb
map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate'
map.signup '/signup', :controller => 'users', :action => 'new'
map.login '/login', :controller => 'sessions', :action => 'new'
map.logout '/logout', :controller => 'sessions', :action => 'destroy'

5. 修改配置文件:

#config/environments.rb
config.active_record.observers = :user_observer

6. 增加邮件通知功能(这里用的是gmail):

$script/plugin install http://svn.douglasfshearer.com/rails/plugins/action_mailer_optional_tls
#config/environment.rb
require 'smtp_tls'
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.default_charset = "utf-8"
ActionMailer::Base.smtp_settings = {
  :tls => true,
  :address => "smtp.gmail.com",
  :port => "587",
  :authentication => :plain,
  :user_name => "flyerhzm",
  :password => "xxx"
}
#app/models/user_mailer.rb
def setup_email(user)
  @recipients  = "#{user.email}"
  @from        = "flyerhzm@gmail.com"
  @subject     = "www.flyerhzm.com "
  @sent_on     = Time.now
  @body[:user] = user
end

7. 设置需要控制的controller:

#app/controllers/application.rb
include AuthenticatedSystem
#app/controllers/posts_controller
before_filter :login_required

8. 修改layout,增加header:

#app/views/layout/application.html.erb
<% if logged_in? -%>
<%= current_user.login %> |
  <%= link_to '推出', logout_path %>
<% else -%>
  <%= link_to '登录', login_path %> |
  <%= link_to '注册', new_user_path %>
<% end -%>

Posted in  rails plugins


ultrasphinx

ultrasphinx是基于sphinx的rails全文搜索插件。我们将在一个已有的博客系统上增加全文搜索来学习这个插件,

1. 首先确保系统已经安装以下软件: * MySQL 5.0 * Sphinx 0.9.8-dev r1112 * Rails 2.0.2 并且需要安装chronic gem,rails应用使用的是mysql数据库

2. 安装插件:

$script/plugin install -x svn://rubyforge.org/var/svn/fauna/ultrasphinx/trunk
$mkdir config/ultrasphinx
$cp vendor/plugin/ultrasphinx/examples/default.base config/ultrasphinx/

3. 标记需要索引的内容:

#app/models/post.rb
is_indexed :fields => [title, body]
#app/models/comment.rb
is_indexed :fields => [body] 

4. 多model的统计配置:

#config/initializers/ultrasphinx.rb
Ultrasphinx::Search.client_options[:with_subtotals] = true

5. 生成索引,并运行ultrasphinx:

$rake ultrasphinx:configure
$sudo rake ultrasphinx:index
$sudo rake ultrasphinx:daemon:start

6.增加search controller:

$script/generate controller search
#app/controllers/search_controller.rb
class SearchController  ApplicationController
  def index
    @search = Ultrasphinx::Search.new(:query => params[:q],
                                      :class_names => SearchHelper::class_name(params[:category]),
                                      :page => params[:page]|| 1,
                                      :per_page => 10)
    @search.run
  end
end
#app/helpers/search_helper.rb
module SearchHelper
  def output_results(search)
    stat = "搜索结果:"
    search.results.each do |result|
      stat  (render :partial => "#{result.class.to_s.downcase}", :object => result)
    end

    stat << "共" << search.total_entries.to_s << "结果。"

    search.subtotals.each do |category, count|
      stat << SearchHelper::ui_name(category) << ":" << count.to_s << "条结果\t"
    end
    stat
  end

  def self.class_name(category_value)
    r = SEARCH_CATEGORIES.detect do |c|
      c[2] == category_value
    end || SEARCH_CATEGORIES[0]
    r[1]
  end

  def self.ui_name(class_name)
    r = SEARCH_CATEGORIES.detect do |c|
      c[1] == class_name
    end || SEARCH_CATEGORIES[0]
    r[0]
  end

  SEARCH_CATEGORIES = [
    #uiname, classname, uivalue
    ['所有', nil, 'all'],
    ['文章', 'Post', 'post'],
    ['评论', 'Comment', 'comment']
  ].freeze
end

7. 提供搜索页面和搜索结果显示页面:

#app/views/shared/_search.html.erb
<form action="/search" method="get" id="search_form">
  <label for="search_category">类别:</label>
  <select id="search_category" name="category">
    <option value="all" selected="selected">所有</option>
    <option value="post">文章</option>
    <option value="comment">评论</option>
  </select>
  <label for="q">关键字:</label>
  <input type="text" name="q" value="<%= params[:q] %>" id="q">
  <input type="submit" value="搜索">
</form>
#app/views/search/_post.html.erb
文章:<%= post.title %>
<%= post.body %>
#app/views/search/_comment.html.erb
评论:
<%= comment.body %>
#app/views/search/index.html.erb
<%= output_results(@search) %>
<%= will_paginate(@search) %>

8. 中文支持:

#config/ultrasphinx/default.base
ngram_len = 1
ngram_chars = U+4E00..U+9FBB, U+3400..U+4DB5, U+20000..U+2A6D6, U+FA0E, U+FA0F, U+FA11, U+FA13, U+FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27, U+FA28, U+FA29, U+3105..U+312C, U+31A0..U+31B7, U+3041, U+3043, U+3045, U+3047, U+3049, U+304B, U+304D, U+304F, U+3051, U+3053, U+3055, U+3057, U+3059, U+305B, U+305D, U+305F, U+3061, U+3063, U+3066, U+3068, U+306A..U+306F, U+3072, U+3075, U+3078, U+307B, U+307E..U+3083, U+3085, U+3087, U+3089..U+308E, U+3090..U+3093, U+30A1, U+30A3, U+30A5, U+30A7, U+30A9, U+30AD, U+30AF, U+30B3, U+30B5, U+30BB, U+30BD, U+30BF, U+30C1, U+30C3, U+30C4, U+30C6, U+30CA, U+30CB, U+30CD, U+30CE, U+30DE, U+30DF, U+30E1, U+30E2, U+30E3, U+30E5, U+30E7, U+30EE, U+30F0..U+30F3, U+30F5, U+30F6, U+31F0, U+31F1, U+31F2, U+31F3, U+31F4, U+31F5, U+31F6, U+31F7, U+31F8, U+31F9, U+31FA, U+31FB, U+31FC, U+31FD, U+31FE, U+31FF, U+AC00..U+D7A3, U+1100..U+1159, U+1161..U+11A2, U+11A8..U+11F9, U+A000..U+A48C, U+A492..U+A4C6

9. 重新索引和服务:

$rake ultrasphinx:configure
$sudo rake ultrasphinx:index
$sudo rake ultrasphinx:daemon:restart

Posted in  rails plugins


acts_as_taggable_on_steroids

acts_as_taggable_on_steroids是基于DHH写的acts_as_taggable,能够为active record的模型增加tag的功能,根据tag查找模型对象,以及计算tag云。下面的示例中我们将为博客系统增加tag功能:

1. 创建工程:

$rails test_acts_as_taggable_on_steroids
$cd test_acts_as_taggable_on_steroids

2. 安装插件:

$script/plugin install http://svn.viney.net.nz/things/rails/plugins/acts_as_taggable_on_steroids

3. 生成post模型、tag和tagging模型:

$script/generate scaffold post title:string body:text
$script/generate acts_as_taggable_migration

4. 为post模型增加tag功能,并添加测试数据:

#app/models/post.rb
acts_as_taggable
#db/migrate/001_create_posts.rb
Post.create(:title => "hello windows", :body => "windows programming")
Post.create(:title => "hello java", :body => "java programming")
Post.create(:title => "hello ruby", :body => "ruby programming")
Post.create(:title => "hello linux", :body => "linux programming")
#db/migrate/002_acts_as_taggable_migration.rb
['windows', 'java', 'ruby', 'linux'].each do |name|
  p = Post.find_by_title("hello #{name}")
  p.tag_list = "#{name}, program"
  p.save
end
$rake db:migrate

5. 调整页面显示:

#app/views/posts/new.html.erb
Tags (splitted by comma)
<%= f.text_field :tag_list %>
#app/views/posts/edit.html.erb
Tags (splitted by comma)
<%= f.text_field :tag_list %>
#app/views/posts/show.html.erb
Tags
<%=h @post.tag_list.join(",") %>
#app/views/posts/index.html.erb
<table>
  <tr>
    <td><%= link_to all, posts_path %></td>
    <% for tag in @tags %>
      <td><%= link_to tag.name, posts_path(:tag_name = tag.name) %></td>
    <% end %>
  </tr>
</table>

6. 修改controller的index方法:

#app/controllers/posts_controller.rb
def index
  @tags = Tag.find(:all)
  if params[:tag_name]
    @posts = Post.find_tagged_with(params[:tag_name], :match_all => true)
  else
    @posts = Post.find(:all)
  end

  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @posts }
  end
end

7. 增加tag云功能:

#app/helper/application_helper.rb
include TagsHelper
#app/controllers/posts_controller.rb
def tag_cloud
  @tags = Post.tag_counts
end
#app/views/posts/index.html.erb
<%= link_to tag cloud, tag_cloud_posts_path %>
#config/routes.rb
map.resources :posts, :collection => { :tag_cloud = :get }
#app/views/posts/tag_cloud.html.erb
<% tag_cloud @tags, %w(css1 css2 css3 css4) do |tag, css_class| %>
  <%= link_to tag.name, posts_path(:tag_name = tag.name), :class = css_class %>
<% end %>
#public/stylesheets/scaffold.css
  .css1 { font-size: 1.0em; }
  .css2 { font-size: 1.2em; }
  .css3 { font-size: 1.4em; }
  .css4 { font-size: 1.6em; }

Tips:

考虑到性能问题,可以为模型的tag做缓冲,只需要在数据库表中增加一列,比如为上文的博客系统增加cache:

$script/generate migration cache_post_tag_list
#db/migrate/003_cache_post_tag_list.rb
add_column :posts, :cached_tag_list, :string

所有的tag名字会组成一个字符串存储在这个字段里,所以不能超过该字段限制的长度。另外需要手动调用save_cached_tag_list才能将tag存储到tags表中

Posted in  rails plugins


Fork me on GitHub