0

I'm working on a small Rails project right now. I'm using Pundit for authorization of controller actions and stuff. The job right now is to use Pundit for the index action and use Pundit's policy_scope in my controller to get the Projects a user can see.

There are 3 ways a user should be able to see a project: - He's the owner - He was invited - The project is public

I've tried several solutions right now but ended up doing the following:

scope :public_or_involved, -> (user) { 
  joins('LEFT JOIN invitations ON invitations.project_id = projects.id').
  where('projects.is_public = TRUE OR projects.owner_id = ? OR invitations.reciever_id = ?', user.id, user.id) 
}

This is the only way I got something like a "public_or_involved" to work with the following pundit scope in project_policy.rb:

class Scope
  attr_reader :user, :scope

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

  def resolve
    scope.public_or_involved(user)
  end
end

So my Question, finally:

Is there an elegant way of doing what I'm doing now? It feels ugly and not rails-like!

bastianwegge
  • 2,435
  • 1
  • 24
  • 30

2 Answers2

0

Caveat, I don't know pundit (I prefer the simpler DSL approach of acl9), so I'm only really converting your query for you, you can usually get Rails to give you a LEFT JOIN with includes(), and you can use this little trick to get a neater OR:

scope :public_or_involved,
  -> (user) { includes(:invitations).where(
    where( is_public: true, owner_id: user.id, invitations: { receiver_id: user.id } ).where_values.reduce(&:or)
  )}
smathy
  • 26,283
  • 5
  • 48
  • 68
  • Thanks for your answer! Does not work as expected. This produces `SELECT "projects".* FROM "projects" WHERE (("projects"."owner_id" = $1 OR "projects"."is_public" = 't') OR "projects"."receiver_id" = 1633)` what then leads to an exception, since projects does not have a reciever. Error in console: `PG::UndefinedColumn: ERROR: column projects.receiver_id does not exist -> LINE 1: ...wner_id" = $1 OR "projects"."is_public" = 't') OR "projects"...` – bastianwegge Mar 04 '15 at 22:24
  • Oh, I'm sorry, I didn't notice that the table was different for that one. I've edited the query. – smathy Mar 05 '15 at 00:19
-1

In my experience, the solution you have now is the best one. You could use something like Arel, Squeel or MetaWhere to Ruby-fy your SQL strings, but those come with added complexity.

If this is meeting your requirements, I wouldn't worry too much about making it "more Rails-y."

messanjah
  • 8,977
  • 4
  • 27
  • 40