- 数据加载中...
正文
|
||||
Building a Social Networking Website with Ruby on Rails 学习笔记 Posted by Captain Z
<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 评论
|
||||