显示标签为“RailsCasts”的博文。显示所有博文
显示标签为“RailsCasts”的博文。显示所有博文

2008年5月11日星期日

RailsCasts 006 symbol to proc

返回所有project的name,传统写法:
projects = Project.find(:all)
projects.collect { |p| p.name }
使用rails提供的shortcut:
projects.collect(&:name)
刚开始可能会觉得有点weird,不过习惯了就感觉很方便,还可以使用链式操作:
projects.collect(&:name).collect(&:downcase)
而且不止collect方法可以这样用,所有需要跟block的方法都可以用:
projects.all?(&:valid?)
projects.any?(&:valid?)
projects.each(&:save!)
意思是对每个project执行其save!方法,&后面跟的就是要执行的方法名称的symbol。
看完这个episode,不得不叹一句,编程就像是在说话一样,太强大了。

另外,在回复中有读者问到:如果&后的方法有argument的话,还能这样用吗?
作者的回复:Nope, it only works on very simple method calls which don't take an argument. Anything more complicated and you will need to use the full block.

还有老兄问能不能这样写:
ActorNames = Actor.find(:all).collect(&:last_name + ' ' + &:first_name)
作者推荐在actor model中定义一个full_name方法,然后调用这个方法:
ActorNames = Actor.find(:all).collect(&:full_name)

RailsCasts 005 using with scope

接上回episode 004,如果我们要查top 20 tasks而非全部记录,该怎么做呢?
不妨直接告诉聪明的find_incomplete方法:
@tasks = Task.find_incomplete :limit => 20
然后在方法定义中使用with_scope:
def self.find_incomplete(options => {})
with_scope :find => options do
find_all_by_complete(false, :order => 'created_at DESC')
end
end
当然,如果不用with_scope,或者还想传order条件(上面order是写死了的),可以merge options:
def self.find_incomplete(options => {})
find_all_by_complete(false, (:order => 'created_at DESC').merge(options))
end
或者使用reverse_merge:
find_all_by_complete(false, options.reverse_merge(:order => 'created_at DESC'))

在关联查询里,也可以传options进去:
@tasks = @project.tasks.find_incomplete :limit => 20
这里的task查询在两个scope里,一个是@project限定的scope,第二个是:limit限定的scope

RailsCasts 004 move find into model

在controller里:
@tasks = Task.find_all_by_complete(false, :order => 'created_at DESC')
改成:
@tasks = Task.find_incomplete
然后在model里定义incomplete方法,这是一个class方法,前面要加self:
def self.find_incomplete
find_all_by_complete(false, :order => 'created_at DESC')
end
注意方法定义体里的find…方法前不用加self,因为当前的作用域就是model类本身。
到这里都看似很平常,下面神奇的就来了。在episode 003里介绍的关联查询也可以用这里定义的find_incomplete方法:
@project = Project.find(params[:id])
@tasks = @project.tasks.find_all_by_complete(false, :order => 'created_at DESC')
可以改成:
@tasks = @project.tasks.find_incomplete
也就是说,凡是Task的class方法,都可以在@project.tasks这样的关联查询中使用。

RailsCasts 003 find through association

关联关系:
Project has_many Tasks
Task belongs_to Project
传统做法:
@project = Project.find(params[:id])
@tasks = Task.find(:all, :conditions => ['project_id = ? AND complete = ?'], @project.id, false)
Rails做法:
@tasks = @project.tasks.find(:all, :conditions => ['complete = ?'], false)
episode 002介绍的动态方法进一步简化:
@tasks = @project.tasks.find_all_by_complete(false)

RailsCasts 002 dynamic find by methods

传统的查询方法:
@tasks = Task.find(:all, :conditions => ['complete = ?', false])
@tasks = Task.find(:first, :conditions => ['complete = ?', false], :order => 'created_at DESC')
动态查询方法:
@tasks = Taks.find_all_by_complete(false)
@tasks = Taks.find_by_complete(false, :order => 'created_at DESC')
注意第二个,直接把:order这个hash作为第二个参数传进去就可以了。

RailsCasts 001 caching with instance variable

这是RailsCasts系列的笔记。

用实例变量来缓存数据库查询结果,这样就不用每次都访问数据库了:
@current_user ||= User.find(session[:user_id])
但是,实例变量的作用域是一次请求,第二次请求还是会重新去查数据库,得到的结果来给@current_user赋值。