Рельсы 5: проверьте, принадлежит ли идентификатор роли пользователю, принадлежащему current_user (через ассоциацию)

#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)