#ruby-on-rails #arrays #ruby
#ruby-on-rails #массивы #ruby
Вопрос:
В моих контроллерах / common/roles_controller.rb я хотел бы проверить, принадлежит ли конкретная роль (идентификатор) пользователям компании current_user, и если нет, перенаправить на errors_path:
def correct_role
role_user = Role.where(:id => params[:id]).select('user_id').first
company_user = current_user.companies.includes(:users)
redirect_to(errors_path) unless company_user.include? role_user.id
end
Определения:
role_user
— находит идентификатор пользователя для определенного идентификатора роли («user_id» — столбец таблицы ролей)company_user
— находит все идентификаторы пользователей, которые принадлежат компаниям, которые принадлежат current_user
модели/role.rb
belongs_to :user, optional: true, inverse_of: :roles
accepts_nested_attributes_for :user
enum general: { seller: 1, buyer: 2, seller_buyer: 3}, _suffix: true
enum dashboard: { denied: 0, viewer: 1, editer: 2, creater: 3, deleter: 4}, _suffix: true
модели/user.rb
#User has roles
has_many :roles
accepts_nested_attributes_for :roles, reject_if: proc { |attributes| attributes[:name].blank? }
# User has many companies
has_many :accounts, dependent: :destroy
has_many :companies, through: :accounts
модели /account.rb
class Account < ApplicationRecord
belongs_to :company
belongs_to :user
accepts_nested_attributes_for :company, :user
end
модели /company.rb
has_many :accounts, dependent: :destroy
has_many :users, through: :accounts
На данный момент с role_user
помощью и company_user
я могу найти оба идентификатора, однако я не могу выполнить часть проверки. Как мне это сделать правильно, пожалуйста? Спасибо за любую помощь!
Обновить
@sajan code выдает это в консоли, когда я открываю /common/roles/1/edit (идентификатор current_user=1 и должен быть разрешен для редактирования):
Parameters: {"id"=>"1"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.6ms) SELECT COUNT(*) FROM "companies" INNER JOIN "accounts" ON "companies"."id" = "accounts"."company_id" WHERE "accounts"."user_id" = ? [["user_id", 1]]
(0.3ms) SELECT "roles".id FROM "roles" WHERE "roles"."user_id" = ? [["user_id", 1]]
Код @Abhishek Kumar в консоли выдает:
Parameters: {"id"=>"1"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Company Load (0.5ms) SELECT "companies".* FROM "companies" INNER JOIN "accounts" ON "companies"."id" = "accounts"."company_id" WHERE "accounts"."user_id" = ? [["user_id", 1]]
(0.4ms) SELECT "users".id FROM "users" INNER JOIN "accounts" ON "users"."id" = "accounts"."user_id" WHERE "accounts"."company_id" = ? [["company_id", 13]]
Role Load (0.2ms) SELECT "roles"."user_id" FROM "roles" WHERE "roles"."id" = ? ORDER BY "roles"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Обновление v2
Итак, я пытаюсь использовать этот код:
def correct_role
company_user_ids = current_user.companies.map(amp;:user_ids)
role_user = Role.where(:id => params[:id]).select('user_id').first
unless role_user.user_id.in?(company_user_ids)
redirect_to(errors_path)
end
end
однако в любом случае он перенаправляет на errors_path, это то, что у меня есть в консоли:
Parameters: {"id"=>"1"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Company Load (0.5ms) SELECT "companies".* FROM "companies" INNER JOIN "accounts" ON "companies"."id" = "accounts"."company_id" WHERE "accounts"."user_id" = ? [["user_id", 1]]
(0.4ms) SELECT "users".id FROM "users" INNER JOIN "accounts" ON "users"."id" = "accounts"."user_id" WHERE "accounts"."company_id" = ? [["company_id", 13]]
Role Load (0.3ms) SELECT "roles"."user_id" FROM "roles" WHERE "roles"."id" = ? ORDER BY "roles"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Ответ №1:
Кажется, что лучшей логикой было бы определить в модели для current_user ассоциацию через компании и пользователей с ролями.
Затем вы можете проверить:
def correct_role
redirect_to(errors_path) unless current_user.company_user_roles.where(id: params[:id]).exists?
end
Это был бы один оператор SQL, который возвращал бы ноль или одну строку и выполнялся бы очень быстро с соответствующими индексами на месте.
Редактировать:
В company.rb добавьте:
has_many :user_roles, through: :users, source: :roles
К user.rb (предполагая, что current_user является экземпляром этой модели) добавьте:
has_many :company_user_roles, through: :companies, source: :user_roles
Комментарии:
1. Спасибо за предложение. Я добавил модель компании выше. Пожалуйста, можете ли вы привести пример, как должны выглядеть модели? Я совсем новичок 🙂
2. Спасибо, похоже, это работает 🙂 Большое, большое спасибо, что спасли меня. Сообщество Rails потрясает!
3. Нет проблем — если что-то выглядит сложным, это, вероятно, делается неправильно 😉
4. Да, верно! Ваш код работает как шарм, еще раз спасибо 😉
Ответ №2:
Может быть, вы могли бы сделать так:
def correct_role
unless current_user.companies.count > 0 amp;amp; current_user.role_ids.include?(params[:id])
redirect_to(errors_path)
end
end
Комментарии:
1. Спасибо, однако я получаю синтаксическую ошибку: неожиданный идентификатор, ожидающий keyword_end
2. Попробуйте теперь с отредактированным ответом, я удалил один пробел. И ошибка возникает из-за того, что где-то вы пропустили закрытие блока
end
строкой. проверьте это.3. кажется, это близко, но еще нет — пожалуйста, можете ли вы проверить, что консоль выдает мне выше в обновлении?
4. Итак, в чем проблема? Перенаправляет ли он на
errors_path
? Если это так, пожалуйста, проверьте, есть ли у вас рольuser_id = 1
. иcurrent_user
имеет как минимум 1 компанию5. Да, это ошибка.
current_user
имеет ID = 1 иuser_id = 1
, например, в столбцеcurrent_user
таблицы ролей, имеет две роли для редактирования(1, 3)
, поскольку есть два пользователя, принадлежащих компании, где в таблице ролейuser_id = (1, 3)