Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add disallowed_attributes to StrongParametersSupport #842

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

mswiszcz
Copy link

@mswiszcz mswiszcz commented Apr 8, 2024

Hello!

We are using can_can_can with graphql-ruby on our project and recently I've been looking for an option to go through all incoming arguments (InputObject arguments) and allow only those which specific user can send.

When I tried to use permitted_attributes I've stumbled upon a problem with associations as our input object allows to send attributes which are not explicity attributes of a class.

Here's an example that describes it:

def Ability
  def initialize(user)
     can :update, Product, user_id: user.id
     cannot(:update, Product, %i[price description]) { |product| !product.premium? } # only premium products can have price and description updated
  end
end

class Product < ApplicationRecord
  belongs_to :user
  # Product does not have attribute title directly, but it's being stored in separate table with translations   
  translates :title # using globalize
end

class ProductAttributes < Graphql::BaseInputObject
  argument :title, String
  argument :price, Float
  argument :description, String 
end

class UpdateProductMutation < Graphql::BaseMutation
  argument :id, ID, loads: :product
  argument :attributes, ProductAttributes, required: true

  def resolve(product:, attributes:)
    permitted_attrs = (attributes.keys & current_ability.permitted_attributes(:update, product)) # => []
    product.update(attributes.slice(permitted_attrs)) # no title in permitted attrs

    # here by using disallowed_attributes we could easily clean attributes from attributes which someone doesnt have rights to change, and not remove those which are associations
    permitted_attrs = attributes.slice(attributes.keys - current_ability.disallowed_attributes(:update, product) # => [:title]
    product.update()
  end
end

We could obviously expliclity mention that someone can :update, Product, :title but that means whenever we add a translation to a new field, or an association and we miss updating ability.rb it will not allow updating it.

Copy link
Member

@coorasse coorasse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this, but I'd like to have some tests for this feature. Thanks. ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants