varvet / pundit

Minimal authorization through OO design and pure Ruby classes
MIT License
8.24k stars 627 forks source link

Permitted attributes based on the attributes/params #671

Closed andresespinosapc closed 2 years ago

andresespinosapc commented 3 years ago

I want to define the permitted attributes for creating a record based on the same attributes that will be used for creating it. I don't find how to do it in Pundit and I don't know if there is a better way of doing what I want.

I want to create an Order that is associated with a Store. Anyone can create an Order, but if you are creating an Order of your own Store you can create it with additional attributes. So, the store_id is passed as a parameter and if it's the same as the authenticated Store it should permit more parameters.

How can I do that? I'm doing it the wrong way?

andresespinosapc commented 3 years ago

I found a workaround, building an Order record with the needed attributes and pass it to the permitted_attributes method. Like this:

permitted_attributes(Order.new(store_id: params[:order]&.[](:store_id)))

If anyone knows a better way please comment.

dgmstuart commented 3 years ago

@andresespinosapc I'm not sure I understand the scenario - tell me if this simpler example is basically the same as your application:

User A owns Store A User B owns Store B

An order has two parameters: product_id and store_id

If User A creates an order for Store A then the permitted parameters should be [:product_id, :store_id] ...but if User A creates an order for Store B then the permitted parameters should be just [:product_id]

Is that right?

If so then I don't think the permitted_attributes feature is intended to accommodate this: Pundit is fundamentally concerned with making decisions based on users and records, not on the values of parameters.

To be honest I'm not sure strong parameters are intended to accommodate this either: it seems like maybe what you're trying to implement is a function which decides:

Which parameters should be used in the creation of an Order?

...rather than:

Which parameters are permitted to be submitted to the application?

If it were me I'd permit all the parameters which are possible with any combination of user and store, and then have a different layer deal with deciding which of those parameters should be used to create an order: maybe a separate OrderCreator object, or maybe a class method like Order.create_with_store(user, params), or even a private method in the controller.

dgmstuart commented 3 years ago

Or if you really want to have it done using strong parameters, then have different controllers or controller actions for the two different cases: like OwnStoreOrdersController vs OtherStoreOrdersController? 🤷

dgmstuart commented 2 years ago

Closing due to inactivity. Please re-open if you have further insights.