【问题标题】:Rails 6 : Enum within a classRails 6:类中的枚举
【发布时间】:2020-07-03 22:05:32
【问题描述】:

我正在努力在一个班级中使用枚举来制作我的目录,来自这个教程:https://naturaily.com/blog/ruby-on-rails-enum

我的模型:

**app/models/catalog.rb**
class Catalog < ApplicationRecord
  include ArrayToEnumHash
  enum state: array_to_enum_hash(CatalogState::STATES)

  def state
    @state ||= CatalogState.new(read_attribute(:state))
  end
end
**app/models/catalog_state.rb**
class CatalogState
  STATES = %w(incoming in_progress finished).freeze

  def initialize(state)
    @state = state
  end

  # what you need here
end
**app/concerns/array_to_enum_hash.rb**
module ArrayToEnumHash
  extend ActiveSupport::Concern
  def array_to_enum_hash(array)
    result = {}
    v = array.to_enum
    w = array.map {|v| v.to_sym }.to_enum
    loop do
      result[w.next] = v.next
    end
    result
  end
end
**db/schema.rb**
create_enum :catalog_state, [
    "incoming",
    "in_progress",
    "finished",
  ]

create_table "catalogs", force: :cascade do |t|
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.enum "state", enum_name: "catalog_state"
    t.index ["state"], name: "index_catalogs_on_state"
  end

我的目录看起来不错:

#<Catalog:0x00007fe87dbfb810
 id: 3,
 created_at: Thu, 02 Jul 2020 16:52:36 UTC +00:00,
 updated_at: Fri, 03 Jul 2020 19:51:26 UTC +00:00,
 status: "unset",
 auction_type: "internet",
 state: "in_progress">

但是,在我的控制台上,ActiveRecord 不会构建枚举快捷方式:

[5] pry(main)> c.state
=> "in_progress"
[6] pry(main)> c.in_progress?
NoMethodError: undefined method `in_progress?' for #<Catalog:0x00007fe87dbfb810>
from /Users/pierre/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activemodel-6.0.3.2/lib/active_model/attribute_methods.rb:432:in `method_missing'

WTF?

【问题讨论】:

  • 我一定要问create_enumt.enum是从哪里来的?
  • 我的目标是创建直接访问方法。比整数和数组设置更进一步:我设置了哈希 {:incoming=>"incoming", :in_progress=>"in_progress", 而不是数组 ["incoming", "in_progress", "finished"] :finished=>"finished"},这样我就可以直接访问:my_instance.incoming? =&gt; false ,my_instance.incoming!。所以问题是关于辅助设置的,这似乎是正确的但不起作用。
  • 但是你不需要自己做。这是由 Rails 处理的:D,看看docs; “... bang 和谓词方法以及相关的范围现在相应地添加了前缀和/或后缀”。
  • 如果您要赋予该枚举列的用途需要 ActiveRecord 无法提供的东西,您可以使用 gem。否则,我在答案中给出的例子必须足够开始了。
  • 无论如何你都可以,它不直接附加到gem的使用上。不过,我必须提到,如果您要对所有这些“voivodeship”进行硬编码,为什么不将它们存储在您的数据库中呢?这种方法可能有优点,但也有缺点。值得深思。

标签: enums rails-activerecord helper ruby-on-rails-6


【解决方案1】:

您不需要那么多就可以在您的目录表中添加“枚举”列。

class CreateCatalogs < ActiveRecord::Migration[6.0]
  def change
    create_table :catalogs do |t|
      t.string "status"
      t.string "auction_type"
      t.integer "state"
      t.timestamps
    end
  end
end

枚举列可以用 integer 数据类型列表示,t.integer "state"

为了设置枚举值,你可以调用CatalogState中定义的常量:

class Catalog < ApplicationRecord
  enum state: CatalogState::STATES
end

值将是["incoming", "in_progress", "finished"],否则,使用关注点中的辅助方法会像{:incoming=&gt;"incoming", :in_progress=&gt;"in_progress", :finished=&gt;"finished"},并且在那里,Rails 无法推断它们所代表的整数值。

之后你可以试试:

catalog = Catalog.new(id: 3, created_at: 'Thu, 02 Jul 2020 16:52:36 UTC +00:00', updated_at: 'Fri, 03 Jul 2020 19:51:26 UTC +00:00', status: 'unset', auction_type: 'internet', state: 'in_progress')
catalog.valid? # true
catalog.save
Catalog.last
# Catalog Load (0.3ms)  SELECT "catalogs".* FROM "catalogs" ORDER BY "catalogs"."id" DESC LIMIT $1  [["LIMIT", 1]]
# => #<Catalog:0x00007fc4d9448f90 id: 3, status: "unset", auction_type: "internet", state: "in_progress", created_at: Thu, 02 Jul 2020 16:52:36 UTC +00:00, updated_at: Fri, 03 Jul 2020 19:51:26 UTC +00:00>
Catalog.last.in_progress?
# Catalog Load (0.5ms)  SELECT "catalogs".* FROM "catalogs" ORDER BY "catalogs"."id" DESC LIMIT $1  [["LIMIT", 1]]
# => true

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多