Ruby on Rails排序多个活动记录的数组

时间:2018-03-09 02:25:47

标签: ruby-on-rails arrays sorting activerecord

我有两种类型的活动记录(对象):

1。项目

<Project:0x007fd1b3ef3c10
id: 1,
min_price: 1000,
max_price: 2000>

2。财产

<Property:0x007fd1b3ef3c15
id: 1,
price: 1000>

他们在一个阵列[项目,财产,项目等..] 我需要按price对它们进行排序,但如果是项目类型,那么我应该使用min_price。我可以在铁轨上做到这一点吗? 我曾尝试使用sort_by,但无法正常工作。

示例

[
  <project  id:1, min_price:1, max:price:100>,
  <property id:2,     price:5>,
  <project  id:3, min_price:3, max:price:100>,
]

我希望它返回:

[
  <project  id:1, min_price:1, max:price:100>,
  <project  id:3, min_price:3, max:price:100>,
  <property id:2,     price:5>,

]

1 个答案:

答案 0 :(得分:1)

您有多种选择:为这两个模型定义一个通用方法,或者只使用sort_by一个动态决定用于排序的方法的块。看看这个片段:

class Project
  attr_accessor :min_price

  alias_method :sort_price, :min_price

  def initialize(min_price)
    @min_price = min_price
  end
end

class Property
  attr_accessor :price

  alias_method :sort_price, :price

  def initialize(price)
    @price = price
  end
end

collection = [Project.new(10), Property.new(20), Project.new(5), Property.new(7)]
puts collection.sort_by(&:sort_price).inspect

puts(collection.sort_by do |record|
  record.is_a?(Project) ? record.min_price : record.price
end.inspect)

我个人更喜欢使用常用方法的解决方案,因为它更面向对象(遵循多态)。如果你不喜欢污染你的模型,你可以做一个装饰器进行分类:

class SortingItem
  attr_reader :object

  def initialize(object)
    @object = object
  end

  def sort_price
    case @object
    when Project
      @object.min_price
    when Property
      @object.price
    else
      fail ArgumentError, "unknown sorting item - #{object.class}"
    end
  end
end

class Project
  attr_accessor :min_price

  def initialize(min_price)
    @min_price = min_price
  end
end

class Property
  attr_accessor :price

  def initialize(price)
    @price = price
  end
end

def decorate(object)
  SortingItem.new(object)
end

collection = [decorate(Project.new(10)), decorate(Property.new(20)), decorate(Project.new(5)), decorate(Property.new(7))]
puts collection.sort_by(&:sort_price).map(&:object).inspect