I have users
class User < ActiveRecord::Base
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation,
:remember_me, :site_id, :role_name
belongs_to :site
end
sites
class Site < ActiveRecord::Base
has_many :users
has_one :front_page_campaign
end
and front_page_campaigns
class FrontPageCampaign < ActiveRecord::Base
belongs_to :site
end
I’m using cancan to restrict access, so users can only manage front_page_campaigns for their own site:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
case user.role_name
when "super_admin"
# can do everything
can :manage, :all
when "editor"
# can edit content for their site
can [:create, :read, :update], FrontPageCampaign, site_id: user.site_id
end
end
end
This works perfectly for users with role_name super_admin and also for editor on show and edit on front_page_campaigns. But when an editor tries to create a new front_page_campaign, I get a cancan forbidden notice
You are not authorized to access this page.
The standard form offers a dropdown box of all sites, and I guess I need to restrict this to just the user’s own site. How would I go about doing this?
Your authorization issue is solved by adding:
to the editor section of cancan ability init.
To set site_id on the new and create object you can set up a before_filter:
you gotta make sure this fires after the resource is created but before can can authorization.
In your form (if you use the same for superadmin and editor) make the site dropdown selection readonly or hidden if
current_user.role_name == 'editor'.Note that if someone tampers with the form and sends an alien site_id as editor, it will be corrected by the before filter, which is not nice. If you take if out and have
:only => :newthen they will get authorization error by cancan. If you are super pedant, you should instead get a valid response with validation error. You can achieve this by 1) applying the before_filter only to new and 2) say in ability initand 3) add site owner checking to model validation. This is my preferred way, keeping authorization errors for illegal access of existing resources.
hope this answers your question