2015-03-04 3 views
0

Я сейчас работаю над небольшим проектом Rails. Я использую Pundit для авторизации действий контроллера и прочее. Теперь задание - использовать Pundit для действия индекса и использовать Pundit's policy_scope в моем контроллере, чтобы получить проекты, которые пользователь может видеть.Область Rails с сложным SQL-заявлением, включая OR

Есть 3 способа пользователь должен иметь возможность видеть проект: - Он владелец - Он был приглашен - Проект общественного

Я пытался несколько решений прямо сейчас, но в конечном итоге делаю следующее:

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

Это единственный способ, которым я получил нечто вроде «public_or_involved» работать со следующей рамкой пандита в 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 

Так что мой вопрос, наконец:

Есть элегантный способ сделать то, что я делаю сейчас? Это кажется уродливым, а не рельсовым.

ответ

-1

По моему опыту, решение, которое у вас есть сейчас, является лучшим. Вы можете использовать что-то вроде Arel, Squeel или MetaWhere для Ruby-fy в своих строках SQL, но они имеют дополнительную сложность.

Если это соответствует вашим требованиям, я бы не стал слишком беспокоиться о том, чтобы сделать его «больше Rails-y».

+0

Этого не может быть! Серьезно этот материал - это способ НЕ СУХОЙ и нелегкий для чтения :( – wegginho

+0

Я считаю, что его легче читать, чем альтернативы, учитывая текущее состояние Rails + ActiveRecord/Arel/Squeel/Metawhere и т. Д. – messanjah

0

Протест, я не знаю, пандита (я предпочитаю более простой DSL подход acl9), так что я только действительно преобразовать ваш запрос для вас, вы можете получить, как правило, Rails, чтобы дать вам LEFT JOIN с includes(), и вы может использовать эту небольшую уловку, чтобы получить опрятку 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) 
)} 
+0

Спасибо за ваш ответ Не работает так, как ожидалось. Это создает «SELECT» проекты ». * FROM« projects »WHERE ((« проекты ».« Owner_id »= $ 1 ИЛИ« проекты ».« Is_public »= 't') ИЛИ« проекты ». "receiver_id" = 1633) 'что затем приводит к исключению, так как в проектах нет приемника. Ошибка в консоли:' PG :: UndefinedColumn: ERROR: column projects.receiver_id не существует -> LINE 1: ... wner_id "= $ 1 ИЛИ" проекты "." Is_public "= 't') ИЛИ" projects "...' – wegginho

+0

О, извините, я не заметил, что таблица была другой для этого. запрос. – smathy

 Смежные вопросы

  • Нет связанных вопросов^_^