帮我重构ruby下一个代码

时间:2011-08-10 13:33:31

标签: ruby-on-rails ruby

@people = People.scoped
@people = @people.where(...) if ...
@people = @people.where(...) if ...
@people = @people.where(...) if ...
@people = @people.where(...) if ...

是否有任何红宝石现有解决方案可以制作类似

的内容
@people = People.scoped

@people.???? do 
  where(...) if ...
  where(...) if ...
  where(...) if ...
end

PS:谢谢你的回答。但是您提供的解决方案看起来像

def self.conditional_scope
  where(...) if ...
  where(...) if ...
  where(...) if ...
end

我想即使所有“如果”都是真的,我也只会到最后。

我是对的吗?

5 个答案:

答案 0 :(得分:2)

我认为你应该熟悉named_scopes: http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html

它们是可组合的,因此您可以编写如下内容:

People.tall.having_children.older_than(30)

其中“tall”,“having_children”和“older_than”被命名为范围。

答案 1 :(得分:1)

是。您只需将其移至模型:

# Controller
@people = People.find_my_guy

# Model
def self.find_my_guy
  where(...) if ...
  where(...) if ...
  where(...) if ...
end

显然,如果在你的语句中使用了一些环境变量,你需要将它们传递给你的模型:

# Controller
@people = People.find_my_guy(params)

# Model
def self.find_my_guy(params)
  where(:id => params[:id]) if params[:id]
  where('title LIKE (?)', "%#{params[:search]}%") if parmas[:search]
  where(...) if ...
end

就你上一次where而言你是对的,我只能建议在这里进行方法链接(像@socjopata那样({/ p>

# Model
def self.with_name(name)
  where(:name => name) if name.present?
end

def self.with_id_gt(id)
  where('id >= ?', id) if id.to_i > 3
end

# Controller
Post.with_name(parms[:name]).with_id_gt(params[:id])

答案 2 :(得分:1)

def self.conditional_scope
  where(...) if ...
  where(...) if ...
  where(...) if ...
end

然后:

Model.conditional_scope

答案 3 :(得分:1)

如果我理解你的要求,你只想在条件存在的情况下应用每个范围......你可以使用带有lambda的命名范围,然后将它们链接起来:

scope :one, lambda {|condition| condition ? where(...) : {}}
scope :two, lambda {|condition| condition ? where(...) : {}}
...


@people = Person.one(true).two(false)

答案 4 :(得分:0)

也许您正在寻找避免在每个where子句后明确分配新范围的方法?您可能对此railscast感兴趣:http://railscasts.com/episodes/212-refactoring-dynamic-delegator。 Ryan Bates使用委托人来实现这样的代码:

def self.search(params)
  products = scope_builder
  products.where("name like ?", "%" + params[:name] + "%") if params[:name]
  products.where("price >= ?", params[:price_gt]) if params[:price_gt]
  products.where("price <= ?", params[:price_lt]) if params[:price_lt]
  products
end