如何使Rails模型中的default_scope动态化?

时间:2013-12-04 15:22:19

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

在我的一个Rails模型中,我有这个:

class Project < ActiveRecord::Base

  belongs_to :user

  default_scope order("number ASC")

end

现在问题是我希望每个user能够单独设置他或她default_scope。例如,用户A可能想要default_scope order("date ASC"),另一个人可能想要default_scope order("number DESC")

在我的User表格中,我甚至还有用于存储这些值的列:order_columnorder_direction

但是如何让模型中的default_scope动态化?

感谢您的帮助。

4 个答案:

答案 0 :(得分:2)

您不想使用default_scope。你做什么是常规scope

class Post < ActiveRecord::Base
  scope :created_before, ->(time) { where("created_at < ?", time) }
end

Scope | Ruby on Rails

答案 1 :(得分:2)

正如@screenmutt所说,默认范围并不是数据驱动的,它们是模型驱动的。由于此范围将根据每个用户的数据而变化,因此我会使用常规范围。

@fmendez答案非常好,但是它使用了默认范围,我刚才解释了为什么不推荐使用这种方法。

这就是我在你的案子中做的事情:

class Post < ActiveRecord::Base
  scope :user_order, lambda { order("#{current_user.order_column} #{current_user.order_direction}")}
end

此处需要注意的一件非常重要的事情是 SQL注入:由于您在查询中嵌入了current_user.order_columncurrent_user.order_direction,因此必须确保用户只能使用有效数据将这些列提供到数据库中。否则,用户将能够编写不需要的SQL查询。

答案 2 :(得分:1)

你可以这样做:

def self.default_scope
   order("#{current_user.order_column} #{current_user.order_direction}")
end

这应该动态选择存储在current_user的order_columnorder_direction列中的值。

答案 3 :(得分:1)

您可以使用您需要的任何逻辑定义类方法,并将默认范围设置为该方法。类方法在返回关系时与命名范围相同,例如通过返回类似顺序的方法的结果。

例如:

def self.user_ordering
    # user ording logic here
end

default_scope :user_ordering

您可能希望将current_user和current_user = class方法添加到User模型,该模型将请求用户维护在线程局部变量中。您通常会从应用程序控制器设置User模型上的当前用户。这使得current_user可用于所有模型的逻辑,例如排序顺序,并以线程安全的方式进行。