Как сохранить перечисление как строку в базу данных в рельсах
Как создать миграцию в ruby, где значение по умолчанию является строкой, а не целым, я хочу сохранить перечисление в базе данных, но я не хочу хранить его как Integer, потому что тогда нет смысла другое приложение, которое хочет использовать одну и ту же таблицу. Как мне сделать default: "female"
вместо default:0
class AddSexToUsers < ActiveRecord::Migration
def change
add_column :users, :sex, :integer, default: 0
end
end
class User < ActiveRecord::Base
enum sex: [:female, :male]
has_secure_password
end
I
Ответы
Ответ 1
Считывая документацию enum
, вы можете видеть, что Rails использует индекс значений Array
, который объясняется как:
Обратите внимание, что при использовании массива неявное сопоставление значений с целыми числами базы данных происходит из порядка, в котором значения отображаются в массиве.
Но также говорится, что вы можете использовать Hash
:
также можно явно сопоставить отношение между атрибутом и целым числом базы данных с хэшем.
В примере:
class Conversation < ActiveRecord::Base
enum status: { active: 0, archived: 1 }
end
Итак, я тестировал Rails 4.2.4 и sqlite3 и создал класс User
с типом string
для типа пола и Hash
в enum
с string
значениями (я использую fem и малые значения отличаются от женщин и мужчин):
Миграция:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :sex, default: 'fem'
end
end
end
Модель:
class User < ActiveRecord::Base
enum sex: { female: 'fem', male: 'mal' }
end
И в консоли:
u = User.new
#=> #<User id: nil, sex: "fem">
u.male?
#=> false
u.female?
#=> true
u.sex
#=> "female"
u[:sex]
#=> "fem"
u.male!
# INSERT transaction...
u.sex
#=> "male"
u[:sex]
#=> "mal"
Ответ 2
enum
в Rails и enum
type в MySQL есть две разные вещи.
-
enum
в Rails - это всего лишь оболочка вокруг столбца integer
, поэтому вам проще использовать строки в запросах, а не целые. Но на уровне базы данных все преобразуется в целые числа (автоматически Rails), так как это тип столбца.
-
enum
Тип в MySQL - тип столбца, специфичного для поставщика (например, SQLite не поддерживает его, но PostgreSQL делает). В MySQL:
ENUM - это строковый объект со значением, выбранным из списка допустимых значений, которые явно перечислены в спецификации столбца во время создания таблицы.
CREATE TABLE shirts (
name VARCHAR(40),
size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);
INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),
('polo shirt','small');
SELECT name, size FROM shirts WHERE size = 'medium';
+---------+--------+
| name | size |
+---------+--------+
| t-shirt | medium |
+---------+--------+
Для миграции вам необходимо сделать следующее:
class AddSexToUsers < ActiveRecord::Migration
def change
add_column :users, :sex, "ENUM('female', 'male') DEFAULT 'female'"
end
end
Ответ 3
Обычно я делаю следующее:
# in the migration in db/migrate/…
def self.up
add_column :works, :status, :string, null: false, default: 'offering'
end
# in app/models/work.rb
class Work < ApplicationRecord
ALL_STATES = %w[canceled offering running payment rating done].freeze
enum status: ALL_STATES.zip(ALL_STATES).to_h
end
Используя хэш в качестве аргумента для enum
(см. документы), эта строка сохраняет строки в базе данных. В то же время это позволяет вам использовать все классные вспомогательные методы Rails:
w = Work.new
#=> #<Work id: nil, status: "offering">
w.rating?
#=> false
w.offering?
#=> true
w.status
#=> "offering"
w[:status]
#=> "offering"
w.done!
# INSERT transaction...
w.status
#=> "done"
w[:status]
#=> "done"
Ответ 4
Взгляните на этот Gist, Rails не предоставляет его "из коробки", так что вы должны использовать беспокойство:
https://gist.github.com/mani47/86096220ccd06fe46f0c09306e9d382d
Ответ 5
Насколько мне известно, это невозможно в стандартном Rails перечислении. Посмотрите https://github.com/lwe/simple_enum, он более функционально богат, а также позволяет хранить значения enum в виде строк в DB (строка типа столбца, т.е. varchar in термины БД).