Reputation: 2700
To me it seems that ActiveAdmin should check the create authorization mainly in 2 cases:
The UI needs to show the "create new Ticket" button: here, it is useful to check wether the current_user has permission to create a generic Ticket.
Cancancan syntax looks like the following:
user.can?(:create, Ticket)
ActiveAdmin needs to understand if the resource can actually be stored in the db after a form submission: here it is useful to check wether the current user can store that ticket with the values just "typed in" using the ticket form.
Cancancan syntax looks like the following:
user.can?(:create, Ticket.new({author_id: user.id, some: "x", other: "y", values: "z"}))
That's it! So why would ActiveAdmin check the following right before showing the generated "create form" for the user?
user.can?(:create, Ticket.new({author_id: nil, some: nil, other: nil, values: nil}))
What if the current user has only permission to create tickets where author_id = own_user_id
?
The authorization would fail even before seeing the form.
Upvotes: 1
Views: 370
Reputation: 2700
I did override the Data Access class as follows, in order to have it working.
I am:
forced validation before the authorization before saving a resource
ActiveAdmin::ResourceController::DataAccess.module_eval do
def build_resource
get_resource_ivar || begin
resource = build_new_resource
resource = apply_decorations(resource)
run_build_callbacks resource
# this authorization check is the one we don't need anymore
# authorize_resource! resource
set_resource_ivar resource
end
end
end
ActiveAdmin::ResourceController::DataAccess.module_eval do
def save_resource(object)
run_save_callbacks object do
return false unless object.validate # added it
authorize_resource! resource # added it
object.save(validate: false) # disabled validation since i do it 2 lines up
end
end
end
Upvotes: 1
Reputation: 6036
I can't explain why ActiveAdmin was written that way, but I can show you how I've solved a similar problem.
First, you will need to grant your user the ability to create the desired record under all conditions:
# app/models/ability.rb
...
can :create, Ticket
...
This will get your past ActiveAdmin's can?
check and allow the user to see the form. But we need to make sure the author_id
belongs to the current user. To do this, you can use the before_create
callback to set the proper author_id
before saving:
# app/admin/ticket.rb
ActiveAdmin.register Ticket do
...
before_create do |ticket|
ticket.author_id = own_user_id
end
...
end
The above assumes you have a helper method or a variable called own_user_id
that is available to the ActiveAdmin module and returns the proper user id. If you were using Devise, you might substitute current_user.id
for own_user_id
.
I'll admit, this is a not the cleanest solution, but it works. I have implemented something similar in my own projects.
Upvotes: 1