before_filter: require_owner - PullRequest
       8

before_filter: require_owner

7 голосов
/ 22 сентября 2009

У меня есть ряд ресурсов (поездки, расписания и т. Д.) С действиями, которые должны быть ограничены только владельцем ресурса.

Как реализовать код с помощью метода #require_owner, определенного в ApplicationController, для достижения этой цели? В идеале, код будет искать цепочку наследования для владельца, поэтому before_filter будет работать с: комментарий, который принадлежит_то: trip, который принадлежит_то: пользователь.

class TripsController < ApplicationController
  belongs_to :member
  before_filter :require_owner

  ...

end

Ответы [ 4 ]

5 голосов
/ 22 сентября 2009

Я не полностью следую описанию (будет ли комментарий действительно принадлежать владельцу поездки?), Но немного расширяю ответ Джонни, вот пример, который ограничивает контроллер поездки:

class ApplicationController < ActionController::Base
  ...
protected
  # relies on the presence of an instance variable named after the controller
  def require_owner
    object = instance_variable_get("@#{self.controller_name.singularize}")
    unless current_user && object.is_owned_by?(current_user)
      resond_to do |format|
        format.html { render :text => "Not Allowed", :status => :forbidden }
      end
    end
  end
end

class TripsController < ApplicationController
  before_filter :login_required # using restful_authentication, for example
  # only require these filters for actions that act on single resources
  before_filter :get_trip, :only => [:show, :edit, :update, :destroy]
  before_filter :require_owner, :only => [:show, :edit, :update, :destroy]
  ...
protected
  def get_trip
    @trip = Trip.find(params[:id])
  end
end

Предполагается, что модель выглядит следующим образом:

class Trip < ActiveRecord::Base
    belongs_to :owner, :class_name => 'User'
    ...
    def is_owned_by?(agent)
      self.owner == agent
      # or, if you can safely assume the agent is always a User, you can 
      # avoid the additional user query:
      # self.owner_id == agent.id
    end
end

Метод login_required (предоставляемый или основанный на модуле авторизации, таком как restful_authentication или authlogic) гарантирует, что пользователь вошел в систему, и предоставляет пользователю метод current_user, get_trip устанавливает переменную экземпляра отключения, которая затем проверяется в require_owner.

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

class CommentsController < ApplicationController
  before_filter :login_required # using restful_authentication, for example
  before_filter :get_comment, :only => [:show, :edit, :update, :destroy]
  before_filter :require_owner, :only => [:show, :edit, :update, :destroy]

  ...
protected
  def get_comment
    @comment = Comment.find(params[:id])
  end
end

с моделью Comment, которая выглядит следующим образом:

class Comment < ActiveRecord::Base
  belongs_to :trip

  # either 
  #  delegate :is_owned_by?, :to => :trip
  # or the long way:
  def is_owned_by?(agent)
    self.trip.is_owned_by?(agent)
  end
end

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

2 голосов
/ 22 сентября 2009

Есть несколько способов сделать это. Вы обязательно должны проверить плагин acl9 (http://wiki.github.com/be9/acl9/tutorial-securing-a-controller).

Если вы решите, что хотите сделать это самостоятельно, я бы предложил сделать что-то вроде:

class Trip < ...
    def owned_by?(user)
        self.user == user
    end
end 

class Comment < ...
    delegate :owned_by?, :to => :trip
end

# in your comment controller, for example
before_filter :find_comment
before_filter :require_owner
def require_owner
    redirect_unless_owner_of(@commemt)
end

# in your application controller
def redirect_unless_owner_of(model)
    redirect_to root_url unless model.owned_by?(current_user)
end   

Простите, если есть какие-либо синтаксические ошибки =) Надеюсь, это поможет!

0 голосов
/ 24 июля 2012

Или просто используйте унаследованные ресурсы:

InheritedResources также вводит еще один метод begin_of_association_chain. Он в основном используется, когда вы хотите создать ресурсы на основе @current_user, и у вас есть URL-адреса, такие как «account / projects». В таких случаях вы должны выполнить @ current_user.projects.find или @ current_user.projects.build в своих действиях.

Вы можете справиться с этим, просто выполнив:

class ProjectsController < InheritedResources::Base
  protected
    def begin_of_association_chain
      @current_user
    end
end
0 голосов
/ 22 сентября 2009

Acl9 - плагин авторизации. Я бы дал вам ссылку, но на моем iPhone не было ни одной вырезки и вставки. Если никто не предоставит ссылку к тому времени, когда я доберусь до компьютера, я возьму ее для вас Или вы можете гуглить. Какой бы ни. :)

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

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