Rails - 将参数传递给链式范围

时间:2017-12-23 02:50:59

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

我正在试图弄清楚如何将多个范围链接在一起。我要做的是有一个搜索框,它将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 

3 个答案:

答案 0 :(得分:0)

你可以通过在用户控制器中创建一个调用send的函数并给它一个像here

这样的数组来实现。

在用户模型中

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

然后将其称为

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

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

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

希望这有帮助。

答案 1 :(得分:0)

试试这个:

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)

答案 2 :(得分:0)

我能够将参数传递给像这样的范围

  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

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