这个控制器中有DRYer方法吗?

时间:2011-04-14 10:58:25

标签: ruby-on-rails

使用ROR 2.3.8。

这是我的代码:

class CitiesController < ApplicationController  
  def show
    ...
  end

  def western
    @city = City.find(params[:id])

    @spots = Spot.paginate(
      :conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, "Places"], 
      :page => params[:page], 
      :per_page => 20, 
      :order => 'rating_average DESC'
      )
  end

  def middle-east
    @city = City.find(params[:id])

    @spots = Spot.paginate(
      :conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, "Food"], 
      :page => params[:page], 
      :per_page => 20, 
      :order => 'rating_average DESC'
      )
  end

  def asian
    @city = City.find(params[:id])

    @spots = Spot.paginate(
      :conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, "Accommodation"], 
      :page => params[:page], 
      :per_page => 20, 
      :order => 'rating_average DESC'
      )
  end

end

我创建了western.html.erbmiddle-east.html.erbasian.html.erb_shops.html.erb

所以前三个基本上都是空的,但产生_shops.html.erb,以免我重新编码视图布局。

编写控制器有更好的方法吗?

谢谢!

2 个答案:

答案 0 :(得分:3)

在Rails 2.3.X中干掉它的正确方法是模型中的命名范围。控制器中的过度/重复查询是一种代码味道的暗示。如果你不相信我,Jamis Buck已经退缩了! http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model

在您的Spot模型中:

# app/models/spot.rb
named_scope :by_type, lambda { |city, type|
  {:conditions => ["(city=? or state=?) and country=? and shop_type=?", city.name, city.name, city.country, type] }
}

在您的城市控制器中:

#app/contollers/cities_controller.rb
before_filter :fetch_city, :except => :show

def western
  @spots = paginate_spots("Places")
end

....

private

def fetch_city
  @city = City.find(params[:id])
end

def paginate_spots(type)
  Spot.by_type(@city,type).paginate(:page => params[:page], 
    :per_page => 20, 
    :order => 'rating_average DESC'
  )
end

这样做的目的是从控制器中删除大部分查询逻辑。这是一件好事,因为它允许您按城市查找斑点,并在需要时键入其他控制器。分页可能特定于您的单个控制器,因此我倾向于将其从模型内的范围中排除。如果要构建API,则可能限制为50而不是20,例如,并希望按其他方法排序。

答案 1 :(得分:1)

第一种方法:使用before_filter更新:它不适合你(我会把它留在这里用于教育目的)

class CitiesController < ApplicationController  
  before_filter :spots_and_city, :only => [:asian, :western, :middle-east]
  def show
    ...
  end

  def western
  end

  def middle-east
  end

  def asian
  end

  private

  def spots_and_city(type)
    @city = City.find(params[:id])
    @spots = Spot.paginate(
      :conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, "Accommodation"], 
      :page => params[:page], 
      :per_page => 20, 
      :order => 'rating_average DESC'
      )
  end
end

第二种方法使用helper method更新

class CitiesController < ApplicationController  
  helper_method :spots, :city
  def show
    ...
  end

  def western
    @city = city
    @spots = spots("Places")
  end

  def middle-east
    @city = city
    @spots = spots("Food")
  end

  def asian
    @city = city
    @spots = spots("Accommodation")
  end

  private

  def city
    city ||= City.find(params[:id])
  end

  def spots(type)
    spots ||= Spot.paginate(
      :conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, type], 
      :page => params[:page], 
      :per_page => 20, 
      :order => 'rating_average DESC'
      )
  end
end

第三:使用Decent Exposure

  

http://railscasts.com/episodes/259-decent-exposure

在我看来,我更喜欢使用helper_method来完成这项工作。