Open hidr0 opened 2 years ago
In our case, we are permitting the nested attribute parameter in the Rails controller, e.g.
def foo_params
params.require(:foo).permit(:something, { children: [:name] })
end
However, we then get an error:
ActiveRecord::AssociationTypeMismatch:
Child(#158640) expected, got { name: "hello" } which is an instance of ActiveSupport::HashWithIndifferentAccess(#158660)
I think this is because CanCanCan's #assign_attributes
method sets foo.children
to an array of hashes rather than child objects. I figured out a workaround which is to add a virtual setter in the Foo
model:
class Foo < ApplicationRecord
has_many :children
accepts_nested_attributes_for :children
# Work around a CanCanCan issue with accepts_nested_attributes_for.
# https://github.com/CanCanCommunity/cancancan/issues/774
def children=(array)
super(array.map { |o| o.is_a?(Hash) ? Child.new(o) : o })
end
end
This then allows us to verify child attributes in our ability.rb
file, e.g.
can :create, Foo, children: { visible_to: current_user.id }
The above rule would only allow users to call the Foos#create
controller action if they include at least one child in the params that is visible_to the current user (this is just an example of one such rule you could enforce).
It would be great if CanCanCan could figure out where it needs to instantiate child objects, rather than just pass a hash so that this workaround isn't needed.
This is still an issue that I would love to see addressed. For now @tuzz' workaround worked for me, Thank you!
Hello we are trying to write an ability for a model which accepts_nested_attributes.
And I was wondering if CanCanCan can do this. Our check is simple:
parent: { nested: { user_id: user.id}}}
But this does not work, because:
new
CanCanCan builds the parent object only andparent.nested == nil
(so we always get Unauthorised)update
CanCanCan loads the object from the database which means that we are not comparing the ability on the nested object. ( so we always get Authorised)Are we supposed to use CanCanCan to check for abilities using
accepts_nested_attributes
or use another kind of check? We were thinking of deploying model validations, but it really made sense if you try to create a nested object for the wrong user to be a CanCanCan Ability check.