基于计算值对-Rails-资源进行排序

17次阅读

共计 2119 个字符,预计需要花费 6 分钟才能阅读完成。

设置

我最近去了一个移动支付黑客马拉松,并与我 Flock 的 co-founder 一起工作了 reminder app。您输入项目的名称和到期日期。然后,该应用程序会显示您需要多长时间才能完成基于 Clear 启发的绿色到红色光谱的给定任务。原文

作为一个黑客马拉松项目,我们希望保持应用程序简单。它包含一个具有 2 个属性的 Reminder 模型:1) 名称和 2) 您想要完成任务的月份中的某一天。

问题

我到了一个点,我想按项目到期前剩余的天数对项目进行排序。

如果我在数据库中有一个名为 ’days_until_due’ 的列,我可以使用订单方法:

Reminder.order('days_until_due ASC')

但我没有一个名为 ’days_until_due’ 的数据库专栏 ……

这让我问自己:“基于计算值而不是数据库中存储的值对模型进行排序的最佳方法是什么?”

解决方案

谷歌搜索后我偶然发现了一个很好的解决方案。它建议创建一个实例方法来计算值,然后创建一个将查询与 sort_by 方法相结合的类方法。

Step 1:创建实例方法来计算值

在 reminder.rb 中,我创建了一个实例方法,根据项目被支持完成的当天和当前日期,找出项目到期前的天数:

def days_until_due
  today = Time.now
  simple_today = Time.new(today.year, today.month, today.day)
  if day >= today.day
    month_due = today.month
  else
    month_due = today.month + 1
  end
  day_due = Time.new(today.year,month_due,day)
  return ((day_due - simple_today)/(60*60*24)).to_i
end
Step 2:创建一个类方法来查询和排序模型

再次在 reminder.rb 中,我创建了一个类方法,它结合了一个查询,sort_by 和上面的实例方法。

def self.sorted_by_days_until_due
  Reminder.all.sort_by(&:days_until_due)
end

您可能会问自己这一行方法中发生了什么?让我们一步一步地分解它。首先,Reminder.all 返回所有提醒的数组 (未排序)。

Reminder.all.class # => Array

接下来,我在这个数组上调用 sort_by 方法。此方法将块作为参数,并通过将值映射到给定块来生成排序数组。如果没有给出块,则返回枚举器。以下是一个例子:

array = ["Michael", "Adam", "Jen"]

array.sort_by{|word| word.length} # => ["Jen", "Adam", "Michael"] 

array.sort_by # => #<Enumerator: ["Michael", "Adam", "Jen"]:sort_by>

现在你可能会问自己,但 ’&:days_until_due’ 如何转化成块?它与 procs 和 blocks 有关。如果你不熟悉这些术语,你应该看看我写的讨论 ruby 的这些部分的 post。在一个句子中,’&:’ 语法将实例方法转换为 proc,然后将 proc 转换为块,这是 Array#sort_by 作为参数。

下面我将使上面的示例看起来像我在提醒应用程序中使用的方法。

array = ["Michael", "Adam", "Jen"]

# Passing in a block directly
array.sort_by{|word| word.length} # => ["Jen", "Adam", "Michael"] 

# Creating a proc and converting the block to a proc using the '&' syntax
proc = :length.to_proc # => #<Proc:0x007f98a225f700> 
array.sort_by(&proc) # => ["Jen", "Adam", "Michael"]

# Creating a proc and converting the block to a proc in one step
array.sort_by(&:length) # => ["Jen", "Adam", "Michael"]

上面的语法通过将隐式类型转换与 ’&’ 运算符组合起来。‘&’ 运算符用于参数列表,以将 Proc 实例转换为块。如果将运算符与 Proc 实例之外的其他内容组合在一起,则隐式类型转换将尝试使用 to_proc 方法将其转换为 Proc 实例。由于 Symbol#to_proc 存在,当我们在 ’&’ 运算符之后传递符号时,它会转换为 proc,然后转换为块。

回到我原来的问题,所有这些关于 procs 和块和类型转换的讨论都让我创建了以下一行方法:

def self.sorted_by_days_until_due
  Reminder.all.sort_by(&:days_until_due)
end

这个方法允许我在我的视图中简洁地包含一个排序的提醒数组,其中包括:

@reminders = Reminder.sorted_by_days_until_due

现在回到编码!

正文完
 0