乐者为王

Do one thing, and do it well.

使用tabnav插件实现Tab导航

tabnav是rails-widgets中的一个组件。不过我们不需要使用其它的组件,所以我们只要使用omenking创建的tabnav就可以,他已经帮我们把tabnav从rails-widgets中分离出来了。

下载插件:

1
script/plugin install git://github.com/omenking/tabnav.git

生成views/shared/_tabnav.html.erb文件:

1
script/generate tabnav tabnav

添加一个标签页到_tabnav.html.erb中,并且把里面显示每个控制器的代码注释掉:

1
2
3
4
add_tab do |t|
  t.named 'Home'
  t.links_to :controller => 'home', :action => 'index'
end

再添加以下代码到tabs.css文件做些许修饰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
.tabnav {
  background-color: #fff;
  padding: 5px;
  height: 2em;
  font-size: 10pt;
}

.tabnav ul {
  height: 2em;
  margin: 0;
  padding: 0;
}

.tabnav li {
  display: inline;
  line-height: 1.167em;
  padding: 0;
}

.tabnav li a {
  background: #5ec998;
  color: #ebebeb;
  text-decoration: none;
  border: 0.083em solid #fff;
  border-bottom: 0.083em solid #5ec998;
  padding: 0.5em 0.667em 0.417em 0.5em;
  float: left;
}

.tabnav li a.active {
  color: #ebebeb;
  font-weight: bold;
  background: #004000;
  border: 0.083em solid #fff;
  border-bottom: 0.083em solid #004000;
}

.tabnav li a:hover {
  color: #004000;
}

.tabnav li a.active:hover {
  color: #ebebeb;
}

Invalid char '\xxx' in expression

Ruby文件中包含中文字符串,编译时提示错误:

1
2
3
Invalid char '\243' in expression
Invalid char '\254' in expression
Invalid char '\273' in expression

在网上搜索原因是因为Ruby不支持带BOM的UTF-8文件(用16进制编辑器打开会发现最前面有EF BB BF三个隐藏字符)。我用的编辑器是Notepad++,它有个功能是Encoding in UTF-8 without BOM,先删除Ruby文件中的中文字符串,然后选中该选项,再输入中文字符串后编译就可以了。

为Rails应用添加feedback功能

首先,将Rails中的Prototype替换为jQuery。接着安装feedback插件:

1
script/plugin install git://github.com/jsboulanger/feedback.git

生成代码,由于我们用jQuery替换了Prototype,所以要在后面加上--jquery选项:

1
script/generate feedback_form --jquery

在app/views/layouts/application.html.erb中添加:

1
<%= javascript_include_tag :defaults %>

在要添加feedback的页面中加上以下代码:

1
<%= feedback_tab(:position => 'top') %>

然后修改app/models/feedback_mailer.rb中的设置:

1
2
3
4
def feedback(feedback)
  @recipients = 'webmaster@example.com'
  @from = 'noreply@example.com'
  @subject = "[Feedback for example.com] #{feedback.subject}"

这样feedback功能就加上了。

为Rails应用增加RSS输出功能

在EntriesController中增加feed方法,内容如下:

1
2
3
4
5
6
def feed
  @entries = Entry.all
  respond_to do |format|
    format.rss { render :layout => false }  # feed.rss.rxml
  end
end

在app/views/entries中增加feed.rss.rxml视图模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
xml.instruct! "xml", :version => "1.0"
xml.rss "version" => "2.0" do
  xml.channel do
    xml.title "example.com Entries"
    xml.description "Listing Entries for example.com"
    xml.link entries_url

    @entries.each do |entry|
      xml.item do
        xml.title entry.title
        xml.link entry_url(entry)
        xml.description entry.content
        xml.guid entry_url(entry)
      end
    end
  end
end

然后在config/routes.rb中添加:

1
map.feed '/feed', :controller => 'entries', :action => 'feed'

这样,当访问http://example.com/feed时就可看到所有内容的RSS输出了。

用simple_captcha插件实现验证码

simple_captcha是一个可以帮我们在Rails中轻松实现验证码功能的插件,它使用简单,并且支持图片和数字验证。

安装插件

1
2
3
script/plugin install git://github.com/eshopworks/simple_captcha.git
rake simple_captcha:setup
rake db:migrate

在config/routes.rb中添加:

1
map.simple_captcha '/simple_captcha/:action', :controller => 'simple_captcha'

在app/controllers/application_controller.rb中添加:

1
2
ApplicationController < ActionController::Base
  include SimpleCaptcha::ControllerHelpers

验证方式有两种:基于控制器和基于模型。这里使用后者作为示例。

在app/views/entries/new.html.erb的form中加上:

1
<%= show_simple_captcha(:ojbect => 'entry', :label => 'Please type the text from the image.') %>

在app/models/entry.rb中添加:

1
2
class Entry < ActiveRecord::Base
  apply_simple_captcha

将app/controllers/entries_controller.rb中的create方法里的

1
if @entry.save

改为

1
if @entry.save_with_captcha

2011/2/17更新

当看不清楚,需要换个验证码时稍麻烦,需要借助Ajax实现,simple_captcha没有提供这个功能,还好小日本写好了一段代码可以参考:http://d.hatena.ne.jp/kusakari/20080130/1201666383 。不过可惜使用的是Prototype库,花了点时间将它改成了jQuery代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="captcha_image">
  <%= show_simple_captcha(:object => 'entry', :label => 'Please type the text from the image.') %>
</div>
<a href="javascript:void(0);" id="recognize_captcha">I cannot recognize.</a>
<script type="text/javascript">
  $("#recognize_captcha").click(function() {
    $.ajax({
      url: "<%= url_for(:action => 'update_captcha') %>",
      success: function(response) {
        $("#captcha_image").html(response);
      }
    });
  });
</script>

在app/controllers/entries_controller.rb中加上:

1
2
3
def update_captcha
  render :layout => false
end

创建app/views/entries/update_captcha.html.erb,代码如下:

1
<%= show_simple_captcha(:object => "entry", :label => 'Please type the text from the image.') %>

还有就是要在routes.rb中添加个映射,不然会找不到action:

1
map.update_captcha '/update_captcha', :controller => 'entries', :action => 'update_captcha'

is not recognized by the 'identify' command

使用Paperclip时遇到一个问题,在上传图片是一直提示图片临时文件is not recognized by the 'identify' command,检查发现临时文件没有问题,有资料说使用Paperclip.options[:command_path]变量可以解决,试过后无效。

查看日志文件看到有如下错误信息:

1
An error was received while processing: #<Paperclip::NotIdentifiedByImageMagickError

根据这条信息找到了解决方法,就是在has_attached_file后将whiny属性设置为false:

1
:whiny => false

comment for《什么样的Java代码看上去比较专业?》

原文:http://blog.csdn.net/michaellufhl/article/details/5996261

本来是要回复在该博文下面的,结果也不知道CSDN是不是在抽疯,死活提交不上,一直显示“正在提交,请稍后……”,所以就只好贴在这里了。

“用最新的语言特性?”很搞笑,恰恰说明你不够专业,因为这表明你每天都在追逐所谓新的东西,而不是在做真真正正的事。

“充足的代码注释”也不完全正确,关键的注释才是好的,而不必是充足的。你在阅读人家代码的时候有多少时间是在看注释呢,所以说注释一定要写在关键点上,不过这一点大多数人都很难做到。

好的命名非常重要,而不仅仅是命名规范,一个好的命名可以代替大段的注释,一看命名就知道这是干什么用的,这时还需要写注释吗?

再次说一句,CSDN真的真的很垃圾!

Rails中做计划任务

在平时的开发中,经常会遇到一些计划任务的需求。比较了几个不同的插件,觉得rufus-scheduler不错,用法也很简单,支持某个时间点做某事,某个时间段做某事等。

安装插件:

1
gem install rufus-scheduler --source http://gemcutter.org

调用也很简单,在initializers文件夹下新建任务文件task.rb:

1
2
3
4
5
6
7
8
require 'rubygems'
require 'rufus/scheduler'

scheduler = Rufus::Scheduler.start_new
scheduler.cron '0 22 * * 0-6' do
  # every day of the week at 22:00 (10pm)
  puts Time.now
end

Cron格式:

  • 第1列分钟0-59
  • 第2列小时0-23(0表示子夜)
  • 第3列日1-31
  • 第4列月1-12
  • 第5列星期0-6(0表示星期天)
  • 第6列要运行的命令

编写无需注释的代码

英文原文:https://blog.codinghorror.com/coding-without-comments/

如果代码中充满大量注释是好的话,那么在代码中有无数的注释必定是更好的,真的是这样吗?那可未必。过度是好注释变坏的一种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
'*************************************************
' Name: CopyString
'
' Purpose: This routine copies a string from the source
' string (source) to the target string (target).
'
' Algorithm: It gets the length of "source" and then copies each
' character, one at a time, into "target". It uses
' the loop index as an array index into both "source"
' and "target" and increments the loop/array index
' after each character is copied.
'
' Inputs: input The string to be copied
'
' Outputs: output The string to receive the copy of "input"
'
' Interface Assumptions: None
'
' Modification History: None
'
' Author: Dwight K. Coder
' Date Created: 10/1/04
' Phone: (555) 222-2255
' SSN: 111-22-3333
' Eye Color: Green
' Maiden Name: None
' Blood Type: AB-
' Mother's Maiden Name: None
' Favorite Car: Pontiac Aztek
' Personalized License Plate: "Tek-ie"
'*************************************************

我经常遇到注释来自那些开发者,他们似乎没有意识到代码已经告诉我们它是如何工作的;我们需要注释告诉我们它为什么这样工作。代码注释被如此广泛地误解和滥用,你可能会发现自己根本不知道它们是否值得使用。注意你需要的东西。下面是没有任何注释的代码:

1
2
3
4
5
r = n / 2;
while ( abs( r - (n/r) ) > t ) {
  r = 0.5 * ( r + (n/r) );
}
System.out.println( "r = " + r );

知道这段代码做什么吗?它是完全可读的,但它到底做什么?

让我们添加一段注释。

1
2
3
4
5
6
// square root of n with Newton-Raphson approximation
r = n / 2;
while ( abs( r - (n/r) ) > t ) {
  r = 0.5 * ( r + (n/r) );
}
System.out.println( "r = " + r );

这应该就是我想要的,真的是这样吗?这是在完全没有注释和每隔一行代码就有精心格式化的史诗般的注释两个极端之间某种满意的、中间道路的妥协?

不全是。与其添加一段注释,我会重构成这样:

1
2
3
4
5
6
7
8
private double SquareRootApproximation(n) {
  r = n / 2;
  while ( abs( r - (n/r) ) > t ) {
    r = 0.5 * ( r + (n/r) );
  }
  return r;
}
System.out.println( "r = " + SquareRootApproximation(r) );

我没有添加任何注释,然而这段神秘的代码现在是完全可以理解的。

尽管注释本身没有好坏,它们却常常被用作代码的支撑。你应该总是写你的代码就跟注释不存在一样。这会迫使你以你能在人力所及的范围想出最简单、最直白、最自文档化的方式写你的代码。

当你重写、重构和重新架构你的代码多次以使你的开发者同事容易阅读和理解时——当你想象不到任何可能的方式你的代码可以被修改而变得更直接和明显时——那时,也只有在那时,你才不得不添加注释解释你的代码做什么。

正如Steve指出的,这是初级和高级开发者之间的一个关键区别:

在过去,一下子看太多的代码老实说超过了我的接受能力,当我不得不处理它时我通常会试图重写它或者至少添加大量的注释。然而今天,我只是艰难地通过它没有抱怨(太多)。当我脑中有个明确的目标和一段复杂的代码要去写的时候,我花费时间去实现它而不是给自己讲述关于它的故事[在注释里]。

初级开发者依赖注释去讲述故事,当他们应该依赖代码去讲述故事的时候。代码是叙述旁白,它们有其自身的价值,但并不意味着替换(故事里的)情节、人物刻画和背景。

或许这就代码注释不可告人的小秘密:写出好的注释你必须是个好作者。注释不是用于编译器的代码,它们是用来和其他人交流想法的言语。虽然我确实要赞美我的程序员同事,但我不能说和其他人有效沟通正是我们的强项。我看过来自我团队中开发者的三段电子邮件,几乎融化了我的大脑。这些是我们信任的人在我们的代码中写的清晰的、可以理解的注释?我以为我们中的一些人可能会更好地坚持我们的优势——也就是说,为编译器写代码,以尽可能清晰的方式,而把注释仅作为最后采取的手段。

写出好的、有意义的注释是困难的。它和写代码本身一样是门艺术,甚至可能更艺术些。正如Sammy Larbi在注释代码的常见借口里说的,如果你觉得你的代码太过复杂以致没有注释就不能理解,那么你的代码可能只是坏的。重写它直到它不再需要注释。如果经过这些努力后,你仍然觉得注释是必要的,那么务必添加注释。越谨慎越好。

用Rails 2.3打造todolist应用

首先生成项目骨架:

1
2
3
4
rails todolist
cd todolist
script/generate scaffold todo title:string description:text done:boolean due_date:datetime
rake db:migrate

安装认证和授权插件:

1
2
3
4
5
script/plugin install git://github.com/technoweenie/restful-authentication.git restful_authentication
script/generate authenticated user sessions

script/plugin install git://github.com/greenisus/forgot_password.git
script/generate forgot_password password user

然后将include AuthenticatedSystem移到ApplicationController中:

1
2
class ApplicationController < ActionController::Base
  include AuthenticatedSystem

添加Todo和User的关联:

1
2
3
4
5
class Todo < ActiveRecord::Base
  belongs_to :user

class User < ActiveRecord::Base
  has_many :todos

修改TodosController,将Todo和User绑定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class TodosController < ApplicationController
  before_filter :login_required

  def index
    @todos = current_user.todos

  def show
    @todo = current_user.todos.find(params[:id])

  def new
    @todo = Todo.new

  def edit
    @todo = current_user.todos.find(params[:id])

  def create
    @todo = Todo.new(params[:todo])
    @todo.user = current_user

  def update
    @todo = current_user.todos.find(params[:id])

  def destroy
    @todo = current_user.todos.find(params[:id])

创建一个应用的首页:

1
script/generate controller home index

为了可以访问到应用首页,需要删除public/index.html文件,并且在routes.rb中添加:

1
map.root :controller => 'home'

将app/views/layouts下的todos.html.erb改名为application.html.erb,然后添加下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<% if logged_in? -%>
  <div id="user-bar-greeting">
    Logged in as <%= link_to_current_user :content_method => :login %>
  </div>
  <div id="user-bar-action">
    (<%= link_to "Log out", logout_path, { :title => "Log out" } %>)
  </div>
<% else -%>
  <div id="user-bar-action">
    <%= link_to "Log in", login_path, { :title => "Log in" } %> /
     <%= link_to "Sign up", signup_path, { :title => "Create an account" } %>
  </div>
<% end -%>

Todo模型的description字段是text类型,在页面上用textarea表示简单了一点,将它改成使用TinyMCE编辑器。可以使用tinymce_hammer插件来集成。

1
script/plugin install git://github.com/trevorrowe/tinymce_hammer.git

执行以下命令后,将会安装TinyMCE到public/javascript/tiny_mce目录:

1
script/generate tinymce_installation

在layout下的模板中添加下面这条语句:

1
<%= init_tinymce_hammer_if_required %>

将app/views/todos下new.html.erb和edit.html.erb中的

1
<%= f.text_area :description %>

修改为

1
<%= f.tinymce :description, :rows => 10, :cols => 40 %>

去除app/views/todos/index.html.erb中description字段的h方法:

1
<td><%= todo.description %></td><br />

还有就是删除某条Todo后记录就彻底地没了,不能恢复,需要给它加上一剂后悔药,使之可以重新被捞出,acts_as_paranoid插件可以做到这点。

1
2
3
script/plugin install git://github.com/technoweenie/acts_as_paranoid.git
script/generate migration add_deleted_at_to_todos deleted_at:datetime
rake db:migrate

添加acts_as_paranoid到模型中:

1
2
class Todo < ActiveRecord::Base
  acts_as_paranoid

现在,调用这个模型的destroy方法将不会真正地删除记录,只会将记录从视图上移除,在deleted_at里记录删除的时间。当然,你可以在find中使用with_deleted或only_deleted参数得到被隐藏的记录。在Rails 3中在find中使用参数会报ArgumentError,显示如下错误:

1
Unknown key: only_deleted

解决办法是使用以下格式的代码:

1
current_user.todos.only_deleted.find(:all)

至此,一个简单的todolist就算完成了。

代码下载:https://github.com/dohkoos/todolist