如何在rails 3活动记录中链接查询

时间:2012-04-02 02:40:57

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord

我需要根据params数据添加条件。

@users = User.where('id', params[:id]) unless params[:id].nil?
@users = User.where('email', params[:email]) unless params[:email].nil?
@users = User.limit(10)

但由于某种原因它不起作用。 感谢

6 个答案:

答案 0 :(得分:23)

您的每个语句都替换@users变量,并且由于ActiveRecord懒惰地评估每个语句,前两个语句永远不会被调用。

如果您想维护三个单独的查询并以这种方式构建,您可以这样做:

@users = User.limit(10)
@users = @users.where('id', params[:id]) if params[:id]
@users = @users.where('email', params[:email]) if params[:email]

它不是最漂亮的,但它会起作用。但是,我建议将其保留在单个方法调用中并在模型中定义它。

# In the model

def self.by_id_and_email(id, email)
  users = limit(10)
  users = users.where('id', id)       if id.present?
  users = users.where('email', email) if email.present?

  users
end

# In the controller / out of the model

User.by_id_and_email(params[:id], params[:email])

通过这种方式,您可以再次使用该方法,对其进行优化,并针对它编写速度(ier)测试。

答案 1 :(得分:7)

如果未提供参数,您可以向模型中添加不执行任何操作的范围,例如 (范围调用只返回当前范围)

# in the model

def self.by_id(id)
    return scoped unless id.present?
  where(:id => id)
end

def self.by_email(email)
  return scoped unless email.present?
  where(:email => email)
end


# in the controller

User.by_id(params[:id]).by_email(params[:email])

答案 2 :(得分:3)

您可以通过以下方式完成此操作:

wheres = [:id, :email].map{|key| params.has_key?(key) ? {key => params[key]} : {} }\
                      .inject({}){|hash, injected| hash.merge!(injected)}
@users = User.where(wheres).limit(10)

此外,您可以随时将上述内容抽象为范围。

答案 3 :(得分:2)

这是范围的完美案例。请查看此asciicast以获取更深入的教程:http://asciicasts.com/episodes/215-advanced-queries-in-rails-3

通过使用范围,您可以将where子句保留为可以单独重用的单独元素,但也可以像where子句一样链接它们。

答案 4 :(得分:0)

你可以通过像...这样的事情来做到这一点。

if params[:id].exists? && params[:email].exists?
  @users = User.where('id = ? AND email = ?', params[:id], params[:email]).limit(10)
elsif #if only one of id/email exists then...
  @users = User.where( #conditions for only one of id/email ).limit(10)
else
  #raise some errors

答案 5 :(得分:0)

如果您创建范围,例如This is a excellent article that explain this

,实际上会更好

在您的模型中

scope :by_id, -> id { where(id: id) if id.present? }
scope :by_email, -> email { where(email: email) if email.present? }

在您的方法中,您可以这样调用

def my_function()
    User.by_id(id).by_email(email)
end