如何设置当前用户ID只能使用自己的动作

时间:2011-06-05 19:00:54

标签: ruby-on-rails devise cancan

我是Ruby-on-Rails的新手。环顾这个网站和Cancan Guides之后,我可以使用一些帮助。我无法让这个为Cancan和Devise工作。用户(设计)只有价格,因此价格属于用户。

我的数据库中有一个user_id用于我的价格迁移:

  create_table "prices", :force => true do |t|
    t.string   "price_name"
    t.decimal  "price"
    t.date     "date"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "user_id"
  end

我的价格控制器(一切都是脚手架,但user_id与另一个迁移到价格表中分开):

class PricesController < ApplicationController
  before_filter :authenticate_user!



  # GET /prices
  # GET /prices.xml
  def index
    @prices = Price.all

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @prices }
    end
  end

  # GET /prices/1
  # GET /prices/1.xml
  def show
    @price = Price.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @price }
    end
  end

  # GET /prices/new
  # GET /prices/new.xml
  def new
    @price = Price.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @price }
    end
  end

  # GET /prices/1/edit
  def edit
    @price = Price.find(params[:id])
  end

  # POST /prices
  # POST /prices.xml
  def create
    @price = current_user.prices.build(params[:price])

    respond_to do |format|
      if @price.save
        format.html { redirect_to(@price, :notice => 'Price was successfully created.') }
        format.xml  { render :xml => @price, :status => :created, :location => @price }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @price.errors, :status => :unprocessable_entity }
      end
    end
  end

  # PUT /prices/1
  # PUT /prices/1.xml
  def update
    @price = Price.find(params[:id])

    respond_to do |format|
      if @price.update_attributes(params[:price])
        format.html { redirect_to(@price, :notice => 'Price was successfully updated.') }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @price.errors, :status => :unprocessable_entity }
      end
    end
  end

  # DELETE /prices/1
  # DELETE /prices/1.xml
  def destroy
    @price = Price.find(params[:id])
    @price.destroy

    respond_to do |format|
      format.html { redirect_to(prices_url) }
      format.xml  { head :ok }
    end
  end
end

然后这是我的Ability.rb(app / models / ability.rb):

class Ability
  include CanCan::Ability

   def initialize(user)
    user ||= User.new
    if user.admin?
        can :manage, :all
        cannot :destroy, User, :id => current_user.id
    else
        can :manage, Price, :user_id => user.id
    end
   end
end

我的问题是,我如何制作,以便只有当前用户可以编辑或删除他或她自己的价格?我的代码不断让任何登录的用户做任何人的价格。

先谢谢。

更新了有效的代码:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new
    can :manage, Price, :user_id => user.id
  end
end

重要* - 删除(或注释掉)编辑,更新,销毁,创建和新的实例变量(例如@),我想知道为什么我的代码不工作,我删除了以下内容并且它完成了它:

def new
  #  @price = Price.new
def edit
  # @price = Price.find(params[:id])
def create
  # @price = Price.new(params[:price]) or @price = current_user.prices.build(params[:price])
def update
  # @price = Price.find(params[:id])
def destroy
  # @price = Price.find(params[:id])

然后在PriceController的顶部:

class PricesController < ApplicationController
  before_filter :authenticate_user!
  load_and_authorize_resource
  skip_authorize_resource :only => :show

2 个答案:

答案 0 :(得分:3)

您已经定义了权限,但您还必须在控制器和可能的视图中检查它们,以便强制执行它们。

indexshow操作,例如:

def index
  # Check if the current user can actually see the Price index.
  authorize! :index, Price

  @prices = Price.all

  # ...
end

def show
  @price = Price.find params[:id]

  # Check if the current user can actually see the Price.
  authorize! :show, @price

  # ...
end

如您所见,调用遵循格式authorize! :action, object,其中object可以是类本身或其实例。当你有一个可用时,你应该使用后者。

为了简单起见,您只需在控制器中的某处添加此行:

authorize_resource

每次操作都会自动authorize! params[:action], @price || Price@price || Price惯用语意味着@price将被使用,除非它是nil,在这种情况下Price将被使用。

此外,请记住,如果当前用户没有所需的权限,对authorize!的调用将引发CanCan::AccessDenied异常。您应该在ApplicationController

中解除此异常
rescue_from CanCan::AccessDenied do |exception|
  redirect_to root_url, :alert => exception.message
end

查看CanCan Wiki上的Authorizing Controller Actions以获取更多详细信息。

答案 1 :(得分:1)

尝试将一个before_filter放入你的控制器中,并确保用户可以做感兴趣的事情。这可以保护后端。

然后还使用cancan权限隐藏或以其他方式可视地保护前端数据。