Rails - вопрос управления потоком, есть ли лучший способ? - PullRequest
1 голос
/ 06 февраля 2009

Я пытаюсь заблокировать несколько контроллеров в зависимости от их роли и контроллера 'posts' в зависимости от того, назначены ли им ЛЮБЫЕ разрешения. Кажется, это работает, но мне интересно, есть ли чистый способ справиться с этим. Это то, что у меня есть в контроллере приложений, который я называю фильтром до ...

if controller_name == 'users' || 'accounts'
  unless @current_user.master? || @current_user.power?
    render :template => "layouts/no_content"
  end
elsif controller_name == 'posts'
  unless @current_user.permissions.count > 0
    render :template => "layouts/no_content"
  end
end

Заранее спасибо.

Ответы [ 6 ]

7 голосов
/ 06 февраля 2009

Вы не должны создавать фрагмент кода, который проверяет имя контроллера, чтобы выполнить определенное действие в application.rb. Вы должны определить это перед фильтрами только в тех контроллерах, которые в них нуждаются

Сделать 2 метода в ApplicationController:

private
def require_master_or_power_user
  unless @current_user.master? || @current_user.power?
    render :template => "layouts/no_content"
  end
end

def require_some_permisions
  unless @current_user.permissions.count > 0
    render :template => "layouts/no_content"
  end
end

Теперь добавьте это как фильтр перед тем, где вам это нужно:

class UsersController < ApplicationController
  before_filter :require_master_or_power_user
  ...
end

class AccountsController < ApplicationController
  before_filter :require_master_or_power_user
  ...
end

class PostsController < ApplicationController
  before_filter :require_some_permisions
  ...
end

Таким образом, ApplicationController определяет фильтры, но ваши контроллеры должны решать, использовать эти фильтры на самом деле или нет. Суперкласс, такой как ApplicationController, никогда не должен условно ветвить свое выполнение на основе его подклассов. Выбор того, когда использовать предоставленное поведение, является одной из причин, по которой вы хотите создать подкласс в первую очередь.

Это также намного понятнее с точки зрения читабельности кода. Если взглянуть на UsersController, сразу видно, что некоторые вещи с разрешениями происходят, когда вы видите фильтр before с именем, подобным «require_something». При вашем подходе вы не сможете понять это, взглянув на сам код контроллера пользователя.

1 голос
/ 06 февраля 2009

Я настоятельно рекомендую вам придерживаться MVC и OOP и перенести столько же логики, связанной с пользователем, обратно в модель User, как это:

class User < ActiveRecord::Base

def has_permission?
  true if self.master? || self.power? || (self.permissions.count > 1)
end

тогда вы можете просто использовать один фильтр в application.rb:

protected

def check_template 
  render :template => "layouts/no_content" if current_user.has_permission? == true
end

и вызовите его с помощью before_filter, как предложено Squeegy, либо в соответствующих контроллерах, либо на сайте в application_controller.rb

before_filter :check_template

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

0 голосов
/ 07 февраля 2009

Вот плагин для RESTful_ACL ; плагин / драгоценный камень ACL, который я разработал, и он довольно широко используется. Это дает вам свободу создавать свои роли по своему усмотрению, и это очень прозрачно.

0 голосов
/ 06 февраля 2009

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

0 голосов
/ 06 февраля 2009

Короткий маленький рукописный DSL. Даже не проверял код на наличие синтаксических ошибок, но вы получите картину. В вашем приложении контроллер:

before_filter :handle_requirements

def self.requirement(*controllers, &block)
  @_requirements ||= {}
  @_requirements[controllers] = block
end

def handle_requirements
  return unless @_requirements
  @_requirements.each do |controllers, proc|
    if controllers.include?(controller.controller_name)
      restrict_access unless instance_eval(&block)
    end
  end
end

def restrict_access
  render :template => "layouts/no_content"
end

Использование (также в вашем контроллере приложения)

requirement('users', 'accounts') do
  @current_user.master? || @current_user.power?
end

Или просто используйте систему ACL, которую упоминает Радар.

0 голосов
/ 06 февраля 2009

Я бы посоветовал использовать для этого систему ACL: http://github.com/ezmobius/acl_system2

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...