2013-08-29 3 views
2

Последнее обновление: 29 авг. 2013 18:54 ESTКак я могу изменить это, чтобы предотвратить многочисленные запросы к базе данных, чтобы проверить роль пользователя?

У меня есть следующий модуль, определенный и включенный в мою модель. Я использую роллинг-камень, чтобы предоставить роли моих пользователей.

module Permissions::Offer 
    extend ActiveSupport::Concern 

    included do 
    # `user` is a context of security 
    protect do |user, offer| 
     # Admins can retrieve anything 
     if user.has_role? :administrator 
     scope { all } 

     # ... and view, create, update, or destroy anything 
     can :view 
     can :create 
     can :update 
     can :destroy 
     elsif user.present? 
     # Allow to read any field 
     can :view 
     can :create 

     # Checks offered_by_id keeping possible nil in mind 
     # Allow sellers to modify/delete their own offers 
     if offer.try(:offered_by_id) == user.id 
      can :update 
      can :destroy 
     end 
     else 
     # Guests can't read the text 
     cannot :view 
     end 
    end 
    end 
end 

Что я испытываю, что когда я делаю следующее ...

respond_with Offer.restrict!(current_user) 

Он запрашивает таблицу ролей для каждого предложения, которое возвращается. В любом случае, не нужно ли повторять этот запрос при запросе списка предложений? Я уверен, что я мог бы кэшировать ответ, чтобы избежать попадания в базу данных, но я бы предпочел, чтобы он не попал в кеш.

Если я открываю консоль рельсы и сделайте следующее я получаю тот же результат:

current_user = User.first 

Offer.restrict!(current_user).to_a 

я установил пуля драгоценный камень, чтобы увидеть, если он считает ее N + 1 запрос, и он не не обнаруживать его. Я верю, потому что включенный получает вызов каждый раз, когда создается новый экземпляр предложения, он запускает этот вызов для проверки прав доступа. Это в сочетании с тем фактом, что rollify не кэширует его проверки роли пользователя в течение какого-то времени, делает это менее идеальным. Я предполагаю, что это будет сделано, чтобы разрешить изменение ролей «на лету» без необходимости разбирать кеш. На данный момент единственным способом, который я могу решить, является реализация собственного кэширования.

+0

Подумав немного больше, это, кажется, действительно странно для меня, и я думаю, что это ошибка в Rolify. Он должен кэшировать роль при первом попадании. Защитник не может влиять на то, как ваша модель («Пользователь») взаимодействует со своими ассоциациями. Сделайте экземпляр 'User' в консоли. Теперь попробуйте повторно запустить 'has_role? '. Это повторится? – inossidabile

ответ

2

Я открыл проблему с переворачиванием, чтобы узнать, заинтересованы ли они в создании более постоянного решения. Для тех, кто сталкивается с этим, вот что я сделал в то же время.

def has_role?(role) 
    roles = Rails.cache.fetch(roles_for: { object_id: self.object_id }, expires_in: 10.seconds, race_condition_ttl: 2.seconds) { self.roles.map(&:name) } 
    roles.include?(role) 
end 

Это не делает все, что делает настоящий метод, но он подходит для моих целей.

Вот ссылка на источник для тех, кто хочет реализовать что-то подобное на всех методах.

https://github.com/EppO/rolify/blob/master/lib/rolify/role.rb