如何在Ruby on Rails 3中将字符串转换为where子句?

时间:2013-07-16 14:53:21

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

我有这个类方法:

def self.default_column
  "created_at"
end

如何重写以下功能,以便我可以使用default_column方法?

def next
  User.where("created_at > ?", created_at).order('created_at ASC').first
end

我尝试过这些......

def next
  User.where("#{default_column} > ?", default_column).order('#{default_column} ASC').first
end

......但我在这里肯定是错误的,因为它根本不起作用。

感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

您可以使用:

def next
  User.where("#{User.default_column} > ?", self.send(User.default_column)).order("#{User.default_column} ASC").first
end

甚至更好

def next
  klass = self.class # This is supposing you are inside User model
  # Otherwise just use klass = User
  klass.where("#{klass.default_column} > ?", self.send(klass.default_column))
       .order(klass.arel_table[klass.default_column].asc)
end

请注意,如果以这种方式处理方法,则无法将其链接:例如User.where(name: 'something').next

如果你想实现这一点,你必须将next移到def self.next,在这种情况下,你必须将用户的实例传递给它,如下所示:

def self.next(user)
  klass = user.class
  klass.where("#{klass.default_column} > ?", user.send(klass.default_column))
       .order(klass.arel_table[klass.default_column].asc)
end

通过这种方式,您可以编写类似:User.where(name: 'test').next(@user)的内容。您可以选择链接.first直接获取结果,但这样您就无法将其他内容链接起来,例如User.where(name: 'test').next(@user).where(email: 'my@mail.com')

最后,如果你想要纯AREL (为了便携性)

def self.next(user)
  klass        = user.class
  arel         = klass.arel_table
  column       = klass.default_column # This helps cleaning up code
  column_value = user.send(column)

  klass.where(arel[column].gt(column_value))
       .order(arel[column].asc)
end

答案 1 :(得分:2)

def next
  default_column = self.class.default_column
  User
  .where("#{default_column} > ?", send(default_column))
  .order("#{default_column} ASC")
  .first
end