Как настроить только текущий идентификатор пользователя может использовать свои собственные действия - PullRequest
2 голосов
/ 05 июня 2011

Я новичок в Ruby-on-Rails. Я мог бы использовать некоторую помощь после осмотра этого сайта и гидов Канкан. У меня проблемы с тем, чтобы заставить это работать на Cancan и Devise. Пользователь (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])

Тогда на вершине цен контроллер:

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

Ответы [ 2 ]

3 голосов
/ 05 июня 2011

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

Действия index и show, например:

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 для получения более подробной информации.

1 голос
/ 05 июня 2011

попробуйте, возможно, вставить before_filter в свой контроллер и убедиться, что пользователь может сделать интересную вещь.Это защищает серверную часть.

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

...