【问题标题】:Rails: Enums with hashes not returning hash key:valueRails:带有散列的枚举不返回散列键:值
【发布时间】:2020-03-31 04:15:30
【问题描述】:

我正在构建一个 Ruby on Rails 应用程序,其中我的模型属性是静态的,例如 GenderStatus。我决定在模型中将它们定义为enums。我正在使用ruby-enum gem 来定义枚举。

我已将ruby-enum gem 添加到我的项目中,并运行bundle install

gem 'ruby-enum', '~> 0.8.0'

但是,枚举需要被其他各种模型访问,所以我在模型的 concerns 目录中将枚举定义为 modules

# app/models/concerns/status.rb

module Status
  extend ActiveSupport::Concern
  included do
    include Ruby::Enum

    define :ordered, 'Ordered'
    define :cancelled, 'Cancelled'
    define :waiting, 'Waiting'
  end
end

我已将此模块包含在我的 Users 模型中

class User < ApplicationRecord
  include Status
end

我的Users 模型有一列status

create_table "users", force: :cascade do |t|
  t.string "first_name"
  t.string "last_name"
  t.string "status"
  t.datetime "created_at", precision: 6, null: false
  t.datetime "updated_at", precision: 6, null: false
end

但是当我查询rails console中的Status模块时:

Status.all

我得到错误:

NoMethodError (undefined method `all' for Status:Module)

当我还在 rails 控制台中查询 User 模型以获取所有 statuses 时:

User.statuses.all

我得到错误:

ArgumentError (wrong number of arguments (given 2, expected 0..1))

我也不知道如何在视图中使用它

  # app/views/users/_form.html.erb

  <%= form.label :status %><br />
  <%= form.select :status, User.statuses.keys.collect { |status| status },{} %>  

对于如何定义枚举并在用户的表单视图中返回枚举的键值以便可以在表单中选择状态,我将不胜感激。谢谢。

【问题讨论】:

  • Rails already has enumsUser.statuses 定义在哪里?
  • 问题是我想对枚举使用哈希方法,这样键 order 可以为 Order 赋值,我在 rails 枚举中没有看到,它使用整数。另外,我没有在任何地方定义User.statuses。我只是在尝试如何查询Users 表以获取所有statuses
  • 映射到字符串的枚举有什么意义?你想达到什么目的?如果要存储状态的显示方式,那就是decorator 的工作。或者考虑使用user.status.humanize。请注意,Rails 枚举在加载时会在整数和字符串之间进行映射。
  • 我想在视图页面中查看 Order 而不是 order 之类的枚举值。我想在视图页面中看到 Not ordered 而不是 not_ordered。我还希望将 status 的值存储在数据库中,而不是像 0, 1, 2 这样的整数。
  • 我建议使用 Rails 的内置枚举功能并使用支持性 gem,例如 rubydoc.info/gems/translate_enum/0.1.3

标签: ruby-on-rails ruby enums


【解决方案1】:

但是当我在 rails 控制台中查询状态模块时:

Status.all

我得到错误:

NoMethodError (undefined method `all' for Status:Module)

.all 请求 ActiveRecord 类的所有记录。 Status 不是 ActiveRecord 类。它甚至不是一个类,它是一个模块。

至于User.statuses.all,我看不出statuses是在哪里定义的。


Ruby::Enum 添加了一些常量和方法,但 Rails 不知道它们。您必须自己将它们集成到 Rails 中。

Rails already has enums 已集成。

module Status
  extend ActiveSupport::Concern
  included do
    # It will take an Array, but it's good practice to be explicit.
    enum status: {ordered: 0, cancelled: 1, waiting: 2}
  end
end

User.statuses 将返回您的状态的HashWithIndifferentAccess

请注意,这些枚举映射到整数,字符串破坏了枚举的点。将您的状态存储为整数可能会为您节省大量空间。 Rails 将为您处理将整数映射到字符串并返回。

请务必更改您的表格以使用整数状态:t.string "status"。为避免用户处于开启状态,您需要定义默认值或 null: false


我想在视图页面中查看订单而不是订单。我想在视图页面中查看 Notordered 和 not_ordered。我还希望将状态的值存储在数据库中,而不是像 0、1、2 这样的整数。——Promise Preston 12 秒前

数据如何显示的细节不属于数据库。最简单的就是使用humanize

# ordered becomes Ordered. not_waiting becomes Not waiting.
User.statuses.keys.collect { |status| status.humanize }

您可以将其推送到状态模块中。

module Status
  ...

  class_methods do
    def show_statuses
      statuses.keys.collect { |status| status.humanize }
    end
  end
end

User.show_statuses

将其作为选择...

<%= f.select :status, User.statuses.collect { |status,id| [status.humanize,id] } %>

您也可以将其推送到状态中。

module Status
  ...

  class_methods do
    ...

    def statuses_for_select
      statuses.collect { |status,id| [status.humanize,id] }
    end
  end
end

<%= f.select :status, User.statuses_for_select %>

随着您的展示细节变得越来越复杂,您的模型会变得臃肿。然后你会考虑把它推到decorator

【讨论】:

  • 谢谢你。您能否在答案中包括一种我可以更改枚举显示方式的方法,例如使用decoratorsinternationazationnot_ordered 更改为Not ordered。此外,如何在Users 视图中为statuses 执行form.select。我会很感激的。
  • @PromisePreston 完成。
  • 谢谢@schwern。还有,如何为用户视图中的状态进行表单选择。我会很感激的。
  • 我将它用于视图&lt;%= form.select :gender, User.statuses.keys.collect { |status| status.humanize },但我收到此错误ArgumentError ('Not ordered' is not a valid status)。我需要对用户的控制器参数进行任何更改吗?
  • 还有一个问题,既然我使用整数作为枚举,当数据库被导出时,它们的列会显示为 0,1,2,3 还是显示为字符串中的枚举(可读)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 1970-01-01
  • 2015-01-26
  • 2021-11-03
  • 1970-01-01
  • 2016-10-28
相关资源
最近更新 更多