RailsSpace: Building a Social Networking Website with Ruby on Rails 学习笔记

RailsSpace: Building a Social Networking Website with Ruby on Rails>是一本从Ruby on Rails基础教起的实例教程。但与共为实例教程的<Agile Web Development with Rails> 相比,<RailsSpace: Building a Social Networking Website with Ruby on Rails>有着自己明显的特色。后者教授的不仅是Ruby on Rails的语言知识, 而且夹杂了更多的编程技巧和思想,我感觉更适合具有一定Ruby on Rails基础的人员,使之从“知道Ruby on Rails知识”提升到“在实战中运用Ruby on Rails"的新层次。

虽然我看过<Agile Web Development with Rails>, 但还是我在<RailsSpace: Building a Social Networking Website with Ruby on Rails>中发现的新奇的东西:

<%= link_to_unless_current "Home",     :action => "index" %>
原来Rails中还有link_to_unless_current。

MySQL的发音是"My-Ess-Cue-Ell".

YAML 是 Ain’t a Markup Language 的缩写。

rake db:migrate VERSION=0, 可以用来月光宝盒数据库版本。

save比save()有更重的ruby味。

在irb的console中可以使用reload!来重载被修改后的环境(我原来一直是退出来再进一次!)

正则实例:    /^[A-Z0-9._%-]+@([A-Z0-9-]+.)+[A-Z]{2,4}$/i,
这个用来校验email地址。
^:字串行的开始
[A-Z0-9._%-]+:至少一位下列有效字符:大写字母,数字,点,下划线或杆线
@
([A-Z0-9-]+.)+:至少一组以点分隔的带有大写字母,数字或杆线的字串
[A-Z]{2,4}:2至4位的大写字母
$:字串行结束
i:因为电邮地址不区分大小写字母,这个i指定正则不对字母的大小写不感冒。

用户的密码不一定要加密后存到数据库中去。

为了使fieldset/legend HTML标签在IE中正常显示,可能要进行CSS Hack.
/* Hack to get IE to display fieldset/legend correctly */
html fieldset {
  position: relative;
}
html legend {
  position:absolute;
  top: -1em;
  left: .5em;
}
html fieldset {
  position: relative;
  margin-top:1em;
  padding-top:2em;
  padding-bottom: 2em;
}

可以在layout中加入显示debug信息的功能。

分离出SCREEN_NAME_SIZE = 20,PASSWORD_SIZE = 10,EMAIL_SIZE = 30等HTML表格参数,方便统一管理。在view中以下面的方法调用:
<div class="form_row">
<label for="email">Email:</label>
<%= form.text_field :email,
:size => User::EMAIL_SIZE,
:maxlength => User::EMAIL_MAX_LENGTH %>
</div>

inspect可以用来显示post的内容:aise params[:user].inspect

在Ruby中只有false和nil才是false的。

可以为系统的错误指示息做一套漂亮的CSS外衣。如:
/* Error Reporting Styles */
.fieldWithErrors {
  margin: 2px;
   padding: 2px;
   background-color: red;
   display: table;
}
#errorExplanation {
  border: 2px solid red;
  padding: 7px;
  padding-bottom: 12px;
  margin-bottom: 20px;
  background-color: #f0f0f0;
}
#errorExplanation h2 {
  text-align: left;
  font-weight: bold;
  padding: 5px 5px 5px 15px;
  font-size: 12pt;
  margin: -7px;
  background-color: #c00;
  color: #fff;
}
#errorExplanation p {
  color: #333;
  margin-bottom: 0;
  padding: 5px;
}
#errorExplanation ul li {
  font-size: 11pt;
  list-style: square;
}
…………..

rake doc:app可以用来生成实例文档。

title = assigns(:title) 产生 title = @title的效果.

测试的命令:rake test:functionals,rake test:units, rake, rake stats,ruby test/functional/user_controller_test.rb -n /test_login_failure/, rake recent….

关于错误信息,0的使用还有sprintf:
>> @error_messages = ActiveRecord::Errors.default_error_messages; 0
=> 0
>> @error_messages[:too_short]
=> "is too short (maximum is %d characters)"
>> sprintf(@error_messages[:too_short], 17)
=> "is too short (maximum is 17 characters)"

使用数据库作为session储存方案可以让网站更方便地扩展成多服务器网站。使用方法:
1. 运行 rake db:sessions:create
2. 将config/environment.rb, uncomment 中下行的注释#去除:
       config.action_controller.session_store = :active_record_store
3. 运行rake db:migrate
4. 重启服务器。

当发生与session相关的错误时,可以试着清空数据库的session表。

用下列语句来快速校验用户密码。
user = User.find_by_screen_name_and_password(screen_name, password)

session[:user_id]返回的是数值,而not session[:user_id].nil?返回的是boolean值,有时候使用两者程序效果一样,但对编程者本身的头脑逻辑清晰度却会有区别。

使用mixin,将一个通用method放到helper中去,这样不但view中,而且在controller中加入include ApplicationHelper语句后也可以使用这个method.甚至test…

大量使用外套(abstraction layer)!!

user.save和user.save!都可以用来发送将user存储到数据库这一指令。区别在存储失败之后的表现上。user.save失败后只会返回一个false值(可以用if user.save判断), 而一旦user.save!失败,将会产生一个exception错误。所以在使用意图上,允许一定条件下(控制之中的)失败时,用user.save,而期望它一定要成功(不然就要启动应急rescue措施)时,用user.save!.

在一class内可以省略语句中attribute和function里的self关键字(self.id->id),但有一例外,就是在赋值的时候, self.name = "Jom"不能省为name = "Jom",因为后者只会产生一个值为"Jom"的本地变量!

这个实例可以用来解决找不到定义好的变量的问题:<% field_title = nil if not defined?(field_title) -%>

用名词命名controller,用动词命名action.

当发现所有instance变量为nil时,检查一下是不是误用到了RoR的保留字。

将类DB_STRING_MAX_LENGTH = 255的常量放到config/environment.rb文件中,这样可以在全局中引用。

@user.spec["first_name"]和@user.spec.send("first_name")等同于@user.spec.first_name

在rout.rb中加入
map.profile ‘profile/:screen_name’, :controller => ‘profile’, :action => ‘show’
后可以使用  profile_url(:screen_name => ‘foobar’)生成profile的url.
在view之外的地方引用可以先 helper :profile (它和include ProfileHelper的不同点???)
included ProfileHelper 是为了使用 profile_for. partial中引用的话要用helper: profile????

MySQL的TEXT栏不支持默认值。手动设置方法
  def initialize
    super
    QUESTIONS.each do |question|
      self[question] = ""
    end
  end

initial function在class新建instance时会被运行。如果class有上级,会自动继承上次的initialize function. 在子class中加initialize function, 使用super,这样会调用上级initialize function.

生成所有单字母串的方法:
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
或 %w(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)

使用列表样式的实例:
<% @letters.each do |letter| %>
<% letter_class = (letter == @initial) ? "letter_current" : "letter" %>
<%= link_to letter, { :action => "index", :id => letter },
:class => letter_class %>
<% end %>

如果action之后还要用到id, rout.rb中没有用到id的url要加入:id=>nil的参数。

pluralize的用法
>> pluralize(0, "box")
=> "0 boxes" #0时用复数
>> pluralize(1, "box")
=> "1 box"
>> pluralize(2, "box")
=> "2 boxes"
>> pluralize(2, "box", "boxen")
=> "2 boxen" #自定义复数形式的方法

原来安装和使用ferret搜索引擎的方法这样简单:
1安装ferret gem
> sudo gem install ferret
2下载安装acts_as_ferret插件
> ruby script/plugin install svn://projects.jkraemer.net/acts_as_ferret/tags/stable/acts_as_ferret
Feeret首次搜索一个model时会耗费一定的时间在Rails的根目录下的index目录生成索引文件。当Ferret出问题时,可以试着在停止网页服务器后删除这个索引目录,让它重新生成索引文件。

合并两个实例列用concat+uniq!
@users.concat(hits.collect { |hit| hit.user }).uniq!

为实例列排序
@users = @users.sort_by { |user| user.spec.last_name }

search form 使用GET request

可用   Spec.find(:all, :conditions => ["gender = :gender", params])来取代Spec.find(:all, :conditions => ["gender = ?", params[:gender]])

改写默认string class的方法在lib/string.rb中
class String
#写自己的method
end

replace能用另一个object取代自己,如:
  def capitalize_each
    space = " "
    split(space).each{ |word| word.capitalize! }.join(space)
  end
  # Capitalize each word in place.
  def capitalize_each!
    replace capitalize_each
  end

写一个检查整数的method:
class Object
  # Return true if the object can be converted to a valid integer.
  def valid_int?
    begin
      Integer(self)
      true
      rescue ArgumentError
      false
    end
  end
end
注意nil.valid_int? 返回 true (Integer(nil) == 0) 但 nil.valid_float? 返回 false(Float(nil) 产生 ArgumentError exception).

使用.errors.add("xxx")的方法写校检method.
  def valid_input?
    @spec = Spec.new
    if @spec.valid? and not zip_code.blank? and location.nil?
      @spec.errors.add(:zip_code, "does not exist in our database")
    end
    unless miles.nil? or miles.valid_float?
      @spec.errors.add("Location radius")
    end
    # The input is valid iff the errors object is empty.
    @spec.errors.empty?
  end
在view中定制引用错误提示信息:
<%= error_messages_for(‘spec’).sub(‘prohibited this spec from being saved’,
‘occurred’) %>

没有super class的module helper中不带任何class.所以要自己require:
module ApplicationHelper
  require ‘string’

使用File.join生成文件目录,以适应不同平台的操作系统?

为了上传图片,必须使用multipart encoding。
<form action="upload" enctype="multipart/form-data" method="post">
<input id="avatar_image" name="avatar[image]" size="30" type="file" />
</form>

PNG (发音:"ping"), 指Portable Network Graphics格式.

使用system("ls")可以调用系统的ls命令。

上传的文件如果小于15K,将是StringIO (string input-output)类,如果大于15K,将是Tempfile (temporary file)。 为了统一两者,可以用File.open(source, "wb") { |f| f.write(@image.read) }将文件写出,"wb" 这里指 "write binary"。

errors.add(:image, "totally doesn’t work")将错误信息加到一个attribute之上。 errors.add_to_base("There’s no freaking way that worked")会将错误信息加到全局。

默认情况下电邮将以text格式发出; 参考:
http://wiki.rubyonrails.org/rails/pages/HowToSendHtmlEmailsWithActionMailer

重写ActiveRecord的子class的initialize function后,可以在保留它的validation function的同时避免将数据写到数据库里。

Active Record的create=new+save, save返回boolean, create直接返回object.

在class内引用此class的class method可以省略class名。

destroy比delete更强大,更适合用来消除Active Record objects.

user.friends
user.requested_friends
user.pending_friends
可以这样连串!!!
has_many :friendships
has_many :friends,
:through => :friendships,
:conditions => "status = ‘accepted’"
has_many :requested_friends,
:through => :friendships,
:source => :friend,
:conditions => "status = ‘requested’"

RESTful式的URLs没有action部分,因为它的格式是:/controller/id;modifier

has_many可以加上order参数:
has_many :posts, :order => "created_at DESC"

内置的time_ago_in_words method,毕竟有!!虽然我不喜欢这个。
Posted <%= time_ago_in_words post.created_at %> ago

format.html用来回应HTML文件请求,format.js可以用来回应Javascript请求。

使用js更新页面
        render :update do |page|
            format.js
        end
action.rjs
          page.hide "add_comment_link_for_post_#{@post.id}"
          page.replace_html "new_comment_form_for_post_#{@post.id}",
          :partial => "new"
使用RJS文件,将controller中view的部分分开来,更合理。

Ajax的运行有可能使客户机,特别是老机子变得很慢甚至瘫痪。

http://wiki.script.aculo.us/scriptaculous/show/CombinationEffectsDemo
中的很多特效中我最喜欢的是
 blind down/up, highlight,puff

如果Ajax运行不正常,可以先检查log文件。

链接的href选项可以为不支持JavaScript的用户提供常规链接。

rake db:migrate RAILS_ENV=production,准备production数据库

- Linux/Apache/mod_proxy_balance/Mongrel 发布方案
- Caching和shared nothing scaling方案
- Subversion 版本管理
- Capistrano 发布版本控制

为网站写一个管理后台??

在console中按production环境启动
> ruby script/console production
> ruby script/console production –sandbox 不修改数据库

查看日志的最后一页:
tail -f log/production.log

在本地访问时Rails会公布全文错误信息,但远程用户会指向public/404.html 或 public/500.html 文件。

更多关注的书:
Practical Rails Social Networking Sites (Expert’s Voice)
The Rails Way (Addison-Wesley Professional Ruby Series)
Pro ActiveRecord: Databases with Ruby and Rails (Pro)
Advanced Rails Recipes: 72 New Ways to Build Stunning Rails Apps
Agile Testing with Ruby and Rails

转载请注明: 转自船长日志, 本文链接地址: http://www.cslog.cn/Content/rails_space_note_1/

相关日志:

  1. Ruby on Rails数据表格关系
  2. Ruby on Rails 的Active Record之Acts As List和Acts As Tree
  3. US States List for Ruby on Rails
  4. Open MDB file on Ubuntu, convert it to CSV, import it to Rails
  5. Rails string字符串相关转换
此条目发表在 Ruby on Rails 分类目录。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已被标记为 *

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>