how to set up current user id only can use their own actions
I am new at Ruby-on-Rails. I could use some help after looking around at this site and Cancan Guides. I am have trouble getting this to work for Cancan and Devise. the User (Devise) only has Prices, so Price belongs to User.
I have a user_id inside of my database for my Price migration:
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
My Prices Controller ( everything was a scaffolded but the user_id which was separate from another migration into the Price table):
class PricesController < ApplicationC开发者_JS百科ontroller
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
And then this is my 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
My question is, how do i make it so only the current user can to edit or delete his or hers own Prices? My code keeps letting any User who is logged in do anything with anyone's Prices.
Thanks in advanced.
Updated code that works:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
can :manage, Price, :user_id => user.id
end
end
important* - remove (or comment out) edit,update,destroy,create and new instance variables (e.g. @), i was wondering why my code wasn't working and i removed the following and it did it:
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])
Then at top of PricesController:
class PricesController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
skip_authorize_resource :only => :show
You have defined your permissions, but you must also check for them in your controllers and possibly views in order to enforce them.
The index
and show
actions, for example:
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
As you can see, the call follows the format authorize! :action, object
, where object
can be the class itself or an instance of it. You should use the latter when you have one available.
To make this easy, you can just add this line somewhere in your controller:
authorize_resource
And it will automatically do authorize! params[:action], @price || Price
for every action. The @price || Price
idiom means @price
will be used unless it is nil
, in which case Price
will be used.
Additionally, keep in mind that the call to authorize!
will raise a CanCan::AccessDenied
exception should the current user not have the required permissions. You should rescue from this exception in ApplicationController
:
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, :alert => exception.message
end
Check out the Authorizing Controller Actions on the CanCan Wiki for more detailed information.
try putting a before_filter into your controller perhaps, and make sure that the user can do the thing of interest. That protects the backend.
Then also use the cancan permissions to hide or otherwise visually protect the data on the front end.
精彩评论