Rails можно ли ссылаться на столбец роли enum в таблице User в нескольких таблицах? - PullRequest
0 голосов
/ 13 апреля 2019

У меня есть модель User с атрибутом Role, который я определил с помощью enum.

enum role: {'Instructor': 0, 'Student': 1, 'Other': 2}

Теперь у меня есть еще один инструктор таблиц со ссылками из таблицы пользователей.

У меня есть таблица курса с рекомендациями от инструктора.

Я хочу, чтобы только Инструктор создал Курс, а не какую-либо другую роль.

Я использую Pundit для авторизации. У меня проблема с созданием нового курса.

def create
  ...
  authorize @course

  @course.instructor = Instructor.where(user: current_user).first

Приведенный выше запрос откатывается, но не сохраняет курс.

Любые предложения будут более полезными.

приложение / политика / course_policy.rb

Ошибка отката

app/policies/course_policy.rb

 class CoursePolicy < ApplicationPolicy
  attr_reader :user, :model

  def initialize (user, model)
    @user = user
    @course = model
  end

  def index?
    true
  end

  def show?
    true
  end

  def create?
    @user.Instructor?
  end

  def update?
    @user.Instructor_of? @course
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      scope.all
    end
  end
end

Вывод ошибки отката:

ActiveRecord::AssociationTypeMismatch (Instructor(#70064238051700) expected, got #<ActiveRecord::Relation []> which is an instance of Instructor::ActiveRecord_Relation(#70064238083180)):

app/controllers/courses_controller.rb:31:in `create'
Started POST "/courses" for ::1 at 2019-04-13 06:02:33 +0700
Processing by CoursesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"++6oBiY4MeOHZKyMwAJ8VqF9ACayve5e+cmMg7FqG4dbHVCfDpI3uqVK7g75+auf8OABUTEnXlm9jshWu/50EQ==", "course"=>{"name"=>"Ruby on Rails", "description"=>"jk.jlliyf", "start_date(1i)"=>"2019", "start_date(2i)"=>"4", "start_date(3i)"=>"12", "end_date(1i)"=>"2019", "end_date(2i)"=>"7", "end_date(3i)"=>"12"}, "commit"=>"Create Course"}
  User Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 2], ["LIMIT", 1]]
  ↳ /home/sagar/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98
  Instructor Load (1.8ms)  SELECT  "instructors".* FROM "instructors" WHERE "instructors"."user_id" = $1 ORDER BY "instructors"."id" ASC LIMIT $2  [["user_id", 2], ["LIMIT", 1]]
  ↳ app/controllers/courses_controller.rb:31
   (0.4ms)  BEGIN
  ↳ app/controllers/courses_controller.rb:34
   (0.4ms)  ROLLBACK
  ↳ app/controllers/courses_controller.rb:34
  Rendering courses/new.html.erb within layouts/application
  Rendered courses/_form.html.erb (44.0ms)
  Rendered courses/new.html.erb within layouts/application (46.7ms)
Completed 200 OK in 267ms (Views: 124.6ms | ActiveRecord: 32.4ms)

Модель курса:

app/models/course.rb

    class Course < ApplicationRecord
        belongs_to :instructor
    end

1 Ответ

0 голосов
/ 13 апреля 2019

Судя по ветке комментариев, кажется, что использование модели Instructor не нужно.

Поскольку в своей политике вы уже ограничили действие create значением user с ролью Instructor и никогда не ожидаете, что Instructor будет иметь атрибуты, превышающие user_id, тогда я думаю, что просто сделай:

def create
  ...
  authorize @course
  @course.instructor = current_user
  ...
end

Теперь я держу пари, что Course имеет instructor_id, а не user_id. Но это нормально. Вам просто нужно сделать:

class Course << ApplicationRecord 

  belongs_to :instructor, class_name: 'User' # or whatever your user class name is.

  ...

end

А теперь вы сможете сделать:

@course.instructor

и верните User, который является инструктором курса.

Я также держу пари, что Instructor has_many :courses, что обычно позволяет вам сделать что-то вроде:

@instructor.courses

Итак, вам нужно что-то вроде:

class User << ApplicationRecord 

  has_many :instructed_courses, class_name: 'Course', foreign_key: :instructor_id

  ...

end

И теперь вы сможете делать такие вещи, как:

@user.instructed_courses
current_user.instructed_courses

Я делаю "Instructed_courses", потому что, предположительно, User с ролью Student захочет сделать что-то вроде:

@user.enrolled_courses

Чтобы осуществить это, я думаю, я бы создал:

class StudentCourse < Application 

    belongs_to :enrolled_course, class_name: 'Course'
    belongs_to :student, class_name: 'User' 

end

А потом:

class User << ApplicationRecord 

  has_many :instructed_courses, class_name: 'Course', foreign_key: :instructor_id
  has_many :student_courses, foreign_key: :student_id
  has_many :enrolled_courses, through: :student_courses

  ...

end

А теперь вы должны уметь:

@user.enrolled_courses
current_user.enrolled_courses

Вы, вероятно, также захотите сделать что-то вроде:

class Course << ApplicationRecord 

  belongs_to :instructor, class_name: 'User' # or whatever your user class name is.
  has_many :student_courses, foreign_key: :enrolled_course_id
  has_many :students, through: :student_courses
  ...

end

Так что вы можете сделать:

@course.students

Shazam!

...