代码之家  ›  专栏  ›  技术社区  ›  Roger

如何在Rails中逐步应用命名的_作用域

  •  0
  • Roger  · 技术社区  · 16 年前
    named_scope :with_country, lambad { |country_id| ...}
    
    named_scope :with_language, lambad { |language_id| ...}
    
    named_scope :with_gender, lambad { |gender_id| ...}
    
    if params[:country_id]
      Event.with_country(params[:country_id])
    elsif params[:langauge_id]
      Event.with_state(params[:language_id])
    else 
      ......
      #so many combinations
    end
    

    如果我同时掌握了国家和语言,那么我需要同时运用这两种语言。在我的实际应用程序中,我有8个不同的命名范围,可以根据具体情况应用它们。如何逐步应用命名的_作用域,或者在某个地方保留命名的_作用域,然后在一次测试中应用。

    我试图坚持这样的价值观

     tmp = Event.with_country(1)
    

    但这会立即触发SQL。

    我想我可以写一些像

    if !params[:country_id].blank? && !params[:language_id].blank? && !params[:gender_id].blank?
      Event.with_country(params[:country_id]).with_language(..).with_gender
    elsif country && language
    elsif country &&  gender
    elsif country && gender
     .. you see the problem
    
    6 回复  |  直到 13 年前
        1
  •  2
  •   Matchu    16 年前

    实际上,SQL不会立即启动。虽然我没有费心去查看Rails是如何实现这种魔力的(尽管现在我很好奇),但是在您真正检查结果集的内容之前,查询不会被激发。

    因此,如果您在控制台中运行以下命令:

    wc = Event.with_country(Country.first.id);nil # line returns nil, so wc remains uninspected
    wc.with_state(State.first.id)
    

    您将注意到,没有为第一行触发任何事件查询,而为第二行触发一个大型事件查询。因此,您可以安全地存储 Event.with_country(params[:country_id]) 作为一个变量,稍后再向其添加更多的作用域,因为查询只在末尾激发。

    若要确认这是正确的,请尝试我描述的方法,并检查服务器日志,以确认在页面本身上仅触发一个查询以查找事件。

        2
  •  1
  •   Community Mohan Dere    8 年前
        3
  •  1
  •   mlavandero    13 年前

    我不得不做一些类似的事情,在一个视图中应用了许多过滤器。我所做的是创建名为“带条件的作用域:

    named_scope :with_filter, lambda{|filter| { :conditions => {:field => filter}} unless filter.blank?}
    

    在同一类中,有一个方法从操作接收参数并返回筛选的记录:

    def self.filter(params)
      ClassObject
      .with_filter(params[:filter1])
      .with_filter2(params[:filter2])
    end
    

    这样,您可以使用命名的范围添加所有过滤器,并且根据发送的参数使用这些过滤器。

    我从这里接受了这个想法: http://www.idolhands.com/ruby-on-rails/guides-tips-and-tutorials/add-filters-to-views-using-named-scopes-in-rails

        4
  •  0
  •   Drew Blas    16 年前

    Event.with_country(params[:country_id]).with_state(params[:language_id])

    将起作用,并且在结束前不会启动SQL(如果您在控制台中尝试,它将立即发生,因为控制台将对结果调用。IRL SQL直到最后才会启动)。

    我怀疑您还需要确保每个命名的_scope测试传入内容的存在:

    named_scope :with_country, lambda { |country_id| country_id.nil? ? {} : {:conditions=>...} }
    
        5
  •  0
  •   Garrett    16 年前

    这对于Rails 3来说很容易:

    products = Product.where("price = 100").limit(5) # No query executed yet
    products = products.order("created_at DESC")     # Adding to the query, still no execution
    products.each { |product| puts product.price }   # That's when the SQL query is actually fired
    
    class Product < ActiveRecord::Base
      named_scope :pricey, where("price > 100")
      named_scope :latest, order("created_at DESC").limit(10)
    end
    
        6
  •  0
  •   tadman    16 年前

    简短的答案是根据需要简单地改变范围,根据存在的参数缩小范围:

    scope = Example
    
    # Only apply to parameters that are present and not empty
    if (!params[:foo].blank?)
      scope = scope.with_foo(params[:foo])
    end
    
    if (!params[:bar].blank?)
      scope = scope.with_bar(params[:bar])
    end
    
    results = scope.all
    

    更好的方法是使用类似searchlogic的东西( http://github.com/binarylogic/searchlogic )它为你封装了所有这些。