#SCOPE IT OUT

和前面一样,让我们先来看一段“SAD CODE”。

/app/controllers/tweets_controller.rb

def index
  @tweets = Tweet.find(
              :all,
              :conditions => {:user_id => current_user.id},
              :order => 'created_at desc',
              :limit => 10
             )
  @trending = Topic.find(
                :all,
                :conditions => ["started_trending > ?", 1.day.ago],
                :order => 'mentions desc',
                :limit => 5
               )
  ...
end

我们先来看看@tweets获取这部分,代码是想取得当前用户下面的10条tweet并按照创建时间排序。

通过在model里定义scope来将排序条件转移到model,并且优化上面代码为如下样子:

def index
  @tweets = current_user.tweets.recent.limit(10)
  ...
end

而在tweet model里,添加如下的scope

/app/models/tweet.rb

class Tweet < ActiveRecord::Base
  scope :recent, order('created_at desc')
  ...
end

我们也可以把这个排序条件定义为default_scope 那么我们的查询条件就可以省略recent部分了。

下面我们再来看看对@trending部分的改写,我们先在Topic model中定义scope

/app/models/topic.rb

class Topic < ActiveRecord::Base
  scope :trending,lambda { where('started_trending > ?', 1.day.ago).
                           order('mentions desc')}
  ...

然后修改/app/controllers/tweets_controller.rb代码如下

def index
  @trending = Topic.trending.limit(5)
  ...
end

我们还可以进一步把limit(5)也添加到scope :trending当中 让topic model变成如下样子

/app/models/topic.rb

class Topic < ActiveRecord::Base
  scope :trending,lambda { |num = nil| where('started_trending > ?', 1.day.ago).
                           order('mentions desc')
                           limit(num)}
  ...

我们的tweets_controllers就可以改为如下样子了:

def index
  @trending = Topic.trending(5)
  ...
end