Skip to content

Instantly share code, notes, and snippets.

@slavone
Last active November 14, 2015 10:46
Show Gist options
  • Save slavone/b440199394d257fa492c to your computer and use it in GitHub Desktop.
Save slavone/b440199394d257fa492c to your computer and use it in GitHub Desktop.
changing_user_type_review

С имеющейся у меня схемой БД с изменением типа юзера проблем нет, но есть пара нюансов. При смене типа пользователя нужно удалить текущую запись пользователя во вспомогательной таблице его текущего типа, создать новую запись во вспомогательной таблице его нового типа, и обновить тип и айди в основной таблице user_logins. Нюанс в том, что это должно быть атомарной транзакцией, но ActiveRecord.transaction легко позволяет это сделать. Еще нюанс - при изменении типа пользователя, ID доп. таблиц будут бессмысленно инкрементироваться, еще раз показывая, что было бы неплохо избавиться от этих лишних ключей.

Для обработки этих действий я создал контроллер user_logins_controller, обеспечивающий стандартный RESTful функционал для user_logins(без добавления и удаления). Доступ туда все теми же стандартными фильтрами ограничивается для всех, кроме админов. При переходе на edit, грузится форма с одним единственным выпадающим списком с типами пользователей. При сабмите проверяется, изменился ли тип, и если изменился, то происходит операция замены типа пользователя. Так как атрибуты у них разные, и многие из них валидируются на наличие, то тип пользователя я проверяю через case и для каждого типа создаю новую запись с требуемыми атрибутами. Второй нюанс в том, что при смене типа удаляются старые данные пользователя. Сейчас я это никак не обрабатываю, т.е. просто удаляю старую запись, и создаю новую, заполняя требуемые атрибуты строкой "change this". В реальной системе так делать не вариант. Можно, например, сделать дополнительное поле changed?, делать его true при изменении типа пользователя, и при следующем логине пользователя, если оно true, просить ввести новые данные.

Еще мне пришлось изменить связь владельцев магазинов с товарами. Изначально я сделал связь один ко многим между продавцом и товарами, это казалось мне логичней, чем для каждого товара иметь поле магазин. Но при случае изменения типа пользователся какого-нибудь владельца магазина, его товары бы либо оставались не привязанными к магазину, либо же просто удалялись, если бы связь была dependent: :destroy. Поэтому я убрал связь shop_owner - product, и добавил автоматически заполняемое поле shop_name в таблицу products.

class UserLoginsController < ApplicationController
before_action :only_admins
def index
@users = UserLogin.all
end
def edit
@user = UserLogin.find(params[:id])
end
def update
@user = UserLogin.find(params[:id])
role = role_update_params[:user_type]
if role != @user.user_type
case role
when 'Admin'
UserLogin.transaction do
old_user = @user.user
old_user.destroy
@user.user = Admin.new(first_name: 'Change this',
last_name: 'Change this',
date_of_birth: Date.today)
@user.save
end
when 'ShopOwner'
UserLogin.transaction do
old_user = @user.user
old_user.destroy
@user.user = ShopOwner.new(shop_name: 'Change this')
@user.save
end
when 'Guest'
UserLogin.transaction do
old_user = @user.user
old_user.destroy
@user.user = Guest.new
@user.save
end
end
flash[:info] = "User #{@user.email} role has been updated."
end
redirect_to user_logins_path
end
private
def role_update_params
params.require(:user_login).permit(:user_type)
end
def only_admins
unless logged_in? && current_user.is_admin?
flash[:danger] = "Access denied."
redirect_to root_path
return
end
end
end
.container
.text-center
%h1 Update user role
.row
.col-md-6.col-md-offset-3
= form_for @user do |f|
.form-group
= f.label "Role"
= f.select :user_type, [['Admin', Admin], ['Shop owner', ShopOwner], ['Guest', Guest]]
.actions
= f.submit "Update", class: %w(btn btn-primary),
data: { confirm: 'Are you sure? User profile settings will be reset.' }
.container
.text-center
%h1 All registered users
%br
%table{ class: 'table' }
%tr
%td ID
%td Email
%td Role
%td Management
- if @users.any?
- @users.each do |u|
%tr
%td
= u.id
%td
= u.email
%td
= u.user_type
%td
= link_to "Edit", edit_user_login_path(u)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment