Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Design question #69

Closed
tbuehlmann opened this issue Nov 6, 2013 · 1 comment
Closed

Design question #69

tbuehlmann opened this issue Nov 6, 2013 · 1 comment

Comments

@tbuehlmann
Copy link

Heyhey,

got a smaller design question. I'm having this structure:

Project.has_many :courses
Course.belongs_to :project

as well as a User can organize some (not all) Pojects. When a user can organize a Project, he's able to create (but not destroy) Courses. So, how would I describe the permission check for creating a Course for a specific Project?

Ideas that come to my mind:

class ProjectPolicy < ApplicationPolicy
  # ...

  def create_course?
    @record.organizers.include?(@user)
  end
end

and check via policy(@project).create_course? in the view.

class CoursePolicy < ApplicationPolicy
  # ...

  def create?
    @record.project.organizers.include?(@user)
  end
end

and check via policy(Course.new(project: @project)).create?. As a side note, I can't use @project.courses.build here because I iterate over @project.courses and don't want unsaved records. That's why I use Course.new(...) here.

I like the latter more, but I ponder about instantiating just another Course object for authorization.. Well, any ideas for this rather not that important design question? :) Maybe other ideas than the ones I had?

@thomasklemm
Copy link
Collaborator

Your second approach sounds solid, I'd go with it to keep all policies related to the Course model in a CoursePolicy.

class CoursesController < ApplicationController
  before_action :set_project

  def create
    @course = @project.courses.build(course_params) # or Course.new(project: @project)
    authorize @course # is equal to authorize @course, :create?
    respond_with @course # or if @course.save ... else ... end
  end

  private

  def set_project
    @project = ...
  end
end

In the ApplicationPolicy there should be attr_reader :record, :user defined, so what I like to do in policies is alias the record method to whatever we're talking about, in this case, a record.

class CoursePolicy < ApplicationPolicy
  alias_method :course, :record

  def create?
    course.project && course.project.organizers.include?(user)
  end
end

In Rails, you could use delegate to shorten your query methods even a bit when this pattern repeats.

class CoursePolicy < ApplicationPolicy
  alias_method :course, :record
  delegate :project, to: :course

  def create?
    project && project.organizers.include?(user)
  end
end

Hope this clarifies things, though your second approach is already almost the same. Thoughts anyone? What could we do better?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants