Предметная область
В качестве предметной области я взял модель безопасности приложения (т.е. ее часть). У нас есть базовая сущность Principal(name, description), и три конкретные сущности наследника: User(login, passwordHash, lastLoginDate, expirationDate, accountDisabled), Role, Group. Для данного примера я решил не усложнять модель связями между User, Role и Group.
Реализация
Для реализации STI нам потребуется в таблицу principals добавить зарезервированное поле type и все поля из классов: Principal, User, Role и Group.
Скрипт миграции
Привожу скрипт миграции для таблицы principals.
class CreatePrincipals < ActiveRecord::Migration
def self.up
create_table :principals do |t|
t.column :name, :string, :limit => 64
t.column :description, :string
t.column :account_disabled, :boolean
t.column :last_login_date, :date
t.column :expiration_date, :date
t.column :type, :string, :limit => 48
end
end
def self.down
drop_table :principals
end
end
Модель
Сущность Principal
class Principal < ActiveRecord::Base
end
Сущность User
class User < Principal
end
Сущность Role
class Role < Principal
end
Сущность Group
class Group < Principal
end
Как видим в объявлениях классов модели нет ничего особенного. Обо всем остальном позаботится ActiveRecord.
Примеры работы с моделью
Тепрь можно создавать наши объекты, сохранять в базу данных и выполнять запросы. В качестве примеров приведу тесты модели (они простые, так что прошу не бить ногами). Примеры только для Role и Group, с User-ом аналогично.
Фикстуры для principals
users_role:
id: 100
name: users
description: system users
type: Role
testers_group:
id: 101
name: testers
description: testers group
type: Group
Тест для сущности Role
require 'test_helper'
class RoleTest < ActiveSupport::TestCase
fixtures :principals
test "role_has_type_eq_role_after_save" do
role = Role.new(:name=>"admins",
:description=>"system administrators")
role.save
assert role.id
assert_equal "Role", role.type
end
test "users_role_exists_in_db" do
role = Role.find_by_id(100);
assert_not_nil role
assert_equal 100, role.id
assert_equal "users", role.name
assert_equal "Role", role.type
end
end
Тест для сущности Group
require 'test_helper'
class GroupTest < ActiveSupport::TestCase
fixtures :principals
test "group_has_type_eq_group_after_save" do
group = Group.new(:name=>"developers",
:description=>"developers group")
group.save
assert group.id
assert_equal "Group", group.type
end
test "users_group_exists_in_db" do
group = Group.find_by_id(101);
assert_not_nil group
assert_equal 101, group.id
assert_equal "testers", group.name
assert_equal "Group", group.type
end
end
Как видим все достаточно прозрачно.
Ложка дегтя
Как уже можно было догадаться есть и обратная сторона медали. Контроль соответствия набора значащих полей конкретной сущности лежит целиком на совести программиста. Для среды ActiveRecord значение имеет лишь колонка type. Так, что я вполне могу создать сущность Role с данными User-а. А это не очень хорошо отразится на отношении ко мне
моих коллег. Поэтому в Rails очень важно покрытие кода функциональными тестами.
Жду отзывов, исправлений и предложений.
No comments:
Post a Comment