开发者

Good practice for protecting methods

Being a newbie ROR developer I've been thinking of ways of protecting certain methods to make sure the correct user is updating their own content. Here is an example of my approach.

Would you recommend a cleaner way or better way of doing such tasks?

# Example Controller 
class Owner::PropertiesController < Owner::BaseController

  def index
  end

  etc.....

  def update
    @property = Property.find(params[:id])

    # Check correct owner 
    check_owner(:owner_id => @property.owner_id)

    if @property.update_attributes(params[:property])
      redirect_to([:owner, @property], :notice => 'Property was successfully updated.')
    else
      render :action => "edit"
    end

  end

  def destroy
    @property = Property.find(params[:id])

    # Check c开发者_开发问答orrect owner 
    check_owner(:owner_id => @property.owner_id)

    @property.destroy
    redirect_to(owner_properties_url)
  end

  private

  def check_owner p = {}
    if p[:owner_id] != session[:owner_id]
      redirect_to([:owner, @property], :notice => "Property not found.")
    end
  end


It's one way of doing it, albeit a little clunky IMO. I tend to take the following approach in those situations:

class FoosController < ApplicationController
  before_filter :find_user

  def create
    @foo = @user.foos.build
  end

  def update
    @foo = @user.foos.find(params[:id])
  end

  private

  def find_user
    @user = User.find(session[:current_user_id])
  end
end

It's a lot cleaner, and the intent is obvious: you're only interested in trying to find a Foo that belongs to @user. One of the downsides to this approach is that if ownership rules change, there's a bit of work involved to change it, but I've found it serves me reasonably well.


You could use a gem like declarative_authorization to do this as well. If you want to do it yourself I would recommend simply DRYing up your code a little bit:

class Owner::PropertiesController < Owner::BaseController
  before_filter :check_owner, :only => [:update, :destroy]

  def update
    if @property.update_attributes(params[:property])
      redirect_to([:owner, @property], :notice => 'Property was successfully updated.')
    else
      render :action => "edit"
    end
  end

  def destroy
    @property.destroy
    redirect_to(owner_properties_url)
  end

  private

  def check_owner
    @property = Property.find(params[:id]

    if @property.owner_id != session[:owner_id]
      redirect_to([:owner, @property], :notice => "Property not found.") and return
    end
  end
end

Additionally, you can filter your properties by an owner to ensure that a user who is not the owner can not interact with properties that aren't his/hers. For example:

def update
  @owner = Owner.find(session[:owner_id])
  @property = @owner.properties.find(params[:id])
  redirect_to unauthorized_page and return if @property.nil?
end

This forces the properties that you are searching to be the ones that belong to the session[:owner_id] instead of the entire universe of properties. This means that properties that the session[:owner_id] does not own will not even be considered. You can then put this code into a before_filter as well so that it's reusable in multiple actions.


Consider using the technique discussed here.

Add an association within your user model and query properties only through that association.

property = Property.find(params[:id])
# vs
property = current_user.properties.find(params[:id])
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜