使用Rails 5枚举PG阵列

时间:2017-01-15 09:27:27

标签: ruby-on-rails

我试图将Rails' enum与PostgreSQL的数组列一起使用。

class Post < ActiveRecord::Base
  enum tags: { a: 0, b: 1, c: 2 }, array: true
end

但是上面的代码不起作用

有没有办法在支持array: true的{​​{3}}数组列上使用枚举?

修改

我希望看到以下测试用例通过,但实际上它失败了。

# frozen_string_literal: true

begin
  require "bundler/inline"
rescue LoadError => e
  $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
  raise e
end

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  # Activate the gem you are reporting the issue against.
  gem "activerecord", "5.1.4"
  gem "pg"
end

require "active_record"
require "minitest/autorun"
require "logger"

# Ensure backward compatibility with Minitest 4
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "postgresql", database: "test")
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :products, force: true do |t|
    t.integer :type_delivery, default: [], array: true, limit: 8
  end
end

class Product < ActiveRecord::Base
  enum type_delivery: { a: 1, b: 2, c: 3, d: 5 }, array: true
end

class BugTest < Minitest::Test
  def test_array_enum
    product = Product.create!(type_delivery: %w[a b c])
    assert_equal products.type_delivery, %w[a b c]
  end
end

错误是:

/usr/local/var/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/activerecord-5.1.4/lib/active_record/enum.rb:172:in `block (2 levels) in enum': undefined method `each_with_index' for true:TrueClass (NoMethodError)
    from /usr/local/var/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/activerecord-5.1.4/lib/active_record/enum.rb:171:in `module_eval'
    from /usr/local/var/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/activerecord-5.1.4/lib/active_record/enum.rb:171:in `block in enum'
    from /usr/local/var/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/activerecord-5.1.4/lib/active_record/enum.rb:154:in `each'
    from /usr/local/var/rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/activerecord-5.1.4/lib/active_record/enum.rb:154:in `enum'
    from guides/bug_report_templates/active_record_gem.rb:38:in `<class:Product>'
    from guides/bug_report_templates/active_record_gem.rb:37:in `<main>'

4 个答案:

答案 0 :(得分:2)

您可以使用array_enum个为此用例https://github.com/freeletics/array_enum创建的gem

答案 1 :(得分:0)

由于这个问题仍然没有答案,因此可以这样做:

首先,array: true方法上没有enum选项,只需将其保留。

第二,添加自定义范围以检索与交货匹配的产品

scope :with_delivery_type, ->(*delivery_types) do
  normalized = Array(delivery_types).flatten
  where('delivery_types @> ?', "{#{normalized.join(',')}}")
end

最后但并非最不重要的一点,我建议使用字符串或Postgres枚举类型而不是整数列。整数列是有问题的,因为对于其中一个,要读取它,一个需要写记录的应用程序的源代码(插入时的版本),而第二个则很难删除或替换值。

答案 2 :(得分:0)

Rails的enum api将属性映射到单个整数列。如果需要,可以创建自己的位掩码以支持多个属性(like is often done with user roles)。

认为,您要找的是attributes api,甚至可以实现自定义ActiveRecord :: Type来处理验证。

答案 3 :(得分:-2)

Rails 5 ++

dataset = [['Foo1', 'Foo2', 'Foo3'], ['Foo1', 'Foo2', 'Foo3']]

for _ in xrange(len(dataset)):
    print("Data " + str(_ + 1) + ":"),
    append_tab = False
    for d in dataset[_]:
        if append_tab:
            result = "\t" + d
        else:
            result = d
            append_tab = True
        print (result)