我是一名新手rails开发人员,我有一个项目,其中我使用几个枚举来创建一个内在有序的属性列表.因此,例如:

enum :priority, { low: 10, moderate: 20, high: 30, very_high: 40, }

现在,如果我调用MyClass.priorities.sort,它将按字母顺序对标签进行排序,而不是基于它们关联的整数.这不是什么大问题,因为我只需要在声明中创建顺序,并且它对于DropDown SELECT之类的东西是持久的.但我还发现,我经常将枚举转换为整数,以便在业务逻辑中进行大于或小于的比较(和>=和<=),这会使代码更冗长,可读性更差.例如:

priority_int = MyClass.priorities[priority]
results = MyClass.where('priority >= ?', priority_int)

有没有一种更惯用的方式来列出我所遗漏的固定属性列表?理想情况下,其中内置了比较/排序.这似乎是一件很常见的事情,但我已经在网上闲逛了几天,还没有看到一个明显的 Select .用简洁、枯燥、可读的代码来满足这种需求的最佳方式是什么?

非常感谢!

推荐答案

也许scope个就是你想要的.挑你喜欢的:

class Model < ApplicationRecord
  enum :priority, {low: 10, moderate: 20, high: 30, very_high: 40}

  ##
  # Add scopes, aka class methods. Append `.order(:priority)` if you like
  #
  #   Model.min_priority(:high).pluck(:priority)
  #   #=> ["high", "high", "very_high"]
  #
  scope :min_priority, ->(name) { where("priority >= ?", priorities[name]) }
  scope :max_priority, ->(name) { where("priority <= ?", priorities[name]) }


  ##
  # Add a shortcut method
  #
  #   Model.first.rank > Model.last.rank
  #   #=> false
  #
  def rank
    priority_before_type_cast
  end


  ##
  # Define the methods you need
  #
  #   Model.first.gt(Model.last)
  #   #=> false
  #
  def rank = priority_before_type_cast
  def gt(other)   = (rank >  other.rank)
  def gteq(other) = (rank >= other.rank)
  def lt(other)   = (rank <  other.rank)
  def lteq(other) = (rank <= other.rank)


  ##
  # You could include Comparable into the model, which will give you:
  # <, <=, >, >=, ==, between?, clamp
  # However, `==` method will cause different models with the same priority
  # to be equal each other. Other than that, you can compare your models:
  #
  #   Model.first <= Model.last
  #   #=> true
  #
  alias_method :eq_copy, :==   # copy the == method
  include Comparable
  alias_method :==, :eq_copy   # put it back
  remove_method :eq_copy       # get rid of the witness
  # this defines how your models compare to each other, aka spaceship operator
  def <=> other
    priority_before_type_cast <=> other.priority_before_type_cast
  end
end

您可能不想将Comparable包含在模型中,但仅定义<=>也很有用,因为当您使用sort时,您会比较:

>> Model.all.pluck(:priority)
=> ["low", "moderate", "high", "very_high", "low", "low"]

>> Model.all.sort.pluck(:priority)
=> ["low", "low", "low", "moderate", "high", "very_high"]

sort_by可以在没有额外服务的情况下解决这个问题,而且速度更快.(use 101 if applicable instead):

>> Model.all.sort_by(&:priority_before_type_cast) # or sort_by(&:rank)
=>
[#<Model:0x00007f99f1380b98 id: 1, priority: "low">,
 #<Model:0x00007f99f06ad178 id: 5, priority: "low">,
 #<Model:0x00007f99f06ad0d8 id: 6, priority: "low">,
 #<Model:0x00007f99f06ad358 id: 2, priority: "moderate">,
 #<Model:0x00007f99f06ad2b8 id: 3, priority: "high">,
 #<Model:0x00007f99f06ad218 id: 4, priority: "very_high">]

还有一件事你可以做,以获得任意的顺序:

Model.in_order_of(:priority, [:low, :moderate, :high, :very_high])

Ruby-on-rails相关问答推荐

HTTP:MimeNegotiation::InvalidType(html不是有效的MIME类型):""

是否从已转换为字符串的数组中提取符号?

搜查升级到 4.0.0 和 ActionText::RichText

active_storage.resolve_model_to_route的不同值代表什么意思?

Rails HMAC - 使用应用程序机密作为加密密钥

如何启动 rails 控制台并专门使用测试数据库?

rails s和bundle exec rails s有什么区别?

如何在 Rails 中使用 instance_eval 子句删除验证?

从 Authlogic 迁移到 Devise

Rails 4,使用 ActiveRecord 的原始查询

模型验证中的 Rails 国际化 (I18n):可能与否?

如何在rails中发回js.haml

使用 jQuery 在 Rails 中不显眼的动态表单字段

测试:如何在不损失速度的情况下专注于行为而不是执行?

ActiveRecord 查找现有表索引

设计/Rails - 如何删除特定的 Flash 消息? (登录成功)

ActiveRecord 中多列的索引

从 Rails 控制器获取主机名

用于在多行上链接调用的 Ruby 约定

使用连接的 Ruby on Rails ActiveRecord 查询