【问题标题】:Rails - pass argument to chained scopesRails - 将参数传递给链式作用域
【发布时间】:2017-12-23 02:50:59
【问题描述】:

我试图弄清楚如何将多个范围链接在一起。我想要做的是有一个搜索框,它将 params[:user_search] 传递给控制器​​,该控制器在用户模型中调用 by_keyword 范围。 by_keyword 范围就像我现在拥有的那样工作,但我想让它也搜索我拥有的所有其他范围。所以基本上 by_keyword 范围应该查询用户输入的任何关键字的所有范围。

在我的 users_controller 索引操作中

  if params[:user_search].present? 
    @users = @users.by_keyword(params[:user_search])
  end    

在我的用户模型中

  scope :by_keyword, -> (keyword) { where('experience LIKE ? OR current_job_title LIKE ?', "%#{keyword}%", "%#{keyword}%" ).order(updated_at: :desc) if keyword.present? }

我想找到一种方法将所有这些链接到 by_keyword 范围

  # these scopes call child classes of User such as skills, languages, patents, etc... 

  scope :by_skill, -> (sk) { joins(:skills).distinct.where( 'skills.name LIKE ?', "%#{sk}%" ).order(updated_at: :desc) if sk.present? }  
  scope :by_language, -> (lang) { joins(:languages).distinct.where( 'languages.language LIKE ?', "%#{lang}%" ).order(updated_at: :desc) if lang.present? }  
  scope :by_certification_or_cert_authority, -> (cert) { joins(:certifications).distinct.where( 'certifications.certification_name LIKE ? OR certifications.certification_authority LIKE ?', "%#{cert}%", "%#{cert}%" ).order(updated_at: :desc) if cert.present? }  
  scope :by_education_level, -> (ed) { joins(:qualifications).distinct.where( 'qualifications.education LIKE ?', "%#{ed}%" ).order(updated_at: :desc) if ed.present? }  
  scope :by_university_major, -> (maj) { joins(:qualifications).distinct.where( 'qualifications.university_major LIKE ?', "%#{maj}%" ).order(updated_at: :desc) if maj.present? }  

我读完了http://guides.rubyonrails.org/active_record_querying.html#scopes

他们给出的例子就是这个,但我不知道如何将超过 2 个作用域链接在一起。

class Article < ApplicationRecord
  scope :published,               -> { where(published: true) }
  scope :published_and_commented, -> { published.where("comments_count > 0") }
end 

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-5


    【解决方案1】:

    你可以通过在用户控制器中创建一个函数来调用发送并给它一个像here这样的数组

    在用户模型中

    def self.send_chain(methods)
      methods.inject(self, :send)
    end
    

    然后像这样称呼它

    User.send_chain(["by_skill", "by_language"])
    

    如果你必须发送参数,你可以这样做:

    scopes = ["by_skill", "by_language"]
    parameters = ["clever", "English"]
    result = []
    scopes.each_with_index do |scope, index|
      result = result + User.send(scope, parameters[index])
    end
    

    希望这会有所帮助。

    【讨论】:

    • 我所有的作用域都带参数,如果它们像这样被链接,不知道如何将参数传递到作用域中。
    • hmmmm,我通过制作两个数组得到了另一个想法,第一个包含范围的名称,第二个包含范围的参数,这就像一对一的关系在数组索引之间,并使用索引each_with_index 遍历第一个数组并在每个数组上应用send 函数,并发送第二个数组中的参数并将结果保存在某个变量中,实际上我不知道它是否可以按照您想要的方式链接您的范围,希望您尽快找到解决方案。
    【解决方案2】:

    试试这个:

    scope :all_clild, -> (val) { |val| by_skill(val).or.by_language(val).or.by_certification_or_cert_authority(val).........# all other scopes}
    
    merged_scope = by_keyword.merge(all_clild)
    

    【讨论】:

    • 我收到错误语法错误,意外的“|”。我猜它不喜欢 |val|
    【解决方案3】:

    我能够将参数传递给这样的作用域

      scope :by_keyword, -> (k) { by_skill(k) | by_language(k) | by_certification_or_cert_authority(k) | by_education_level(k) | by_university_major(k)}
    

    我不确定这是否真的被认为是“链接”它们。我猜可能有更好的方法来做到这一点,如果有请告诉我。

    它进行了大量的查询,所以我不确定这是否是明智的性能明智之举,甚至以它们的方式调用这么多范围。这是搜索“CCNA”一词时的结果

      User Load (0.5ms)  SELECT DISTINCT "users".* FROM "users" INNER JOIN "skills" ON "skills"."user_id" = "users"."id" WHERE (skills.name LIKE '%CCNA%') ORDER BY "users"."updated_at" DESC
      User Load (0.5ms)  SELECT DISTINCT "users".* FROM "users" INNER JOIN "languages" ON "languages"."user_id" = "users"."id" WHERE (languages.language LIKE '%CCNA%') ORDER BY "users"."updated_at" DESC
      User Load (0.6ms)  SELECT DISTINCT "users".* FROM "users" INNER JOIN "certifications" ON "certifications"."user_id" = "users"."id" WHERE (certifications.certification_name LIKE '%CCNA%' OR certifications.certification_authority LIKE '%CCNA%') ORDER BY "users"."updated_at" DESC
      User Load (0.5ms)  SELECT DISTINCT "users".* FROM "users" INNER JOIN "qualifications" ON "qualifications"."user_id" = "users"."id" WHERE (qualifications.education LIKE '%CCNA%') ORDER BY "users"."updated_at" DESC
      User Load (0.5ms)  SELECT DISTINCT "users".* FROM "users" INNER JOIN "qualifications" ON "qualifications"."user_id" = "users"."id" WHERE (qualifications.university_major LIKE '%CCNA%') ORDER BY "users"."updated_at" DESC
    

    另外,从安全的角度来看,我不确定允许用户输入一个涉及这么多表的查询是否是一件好事。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-19
      • 2012-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-14
      相关资源
      最近更新 更多