From 12602720a538f2678562580a6f3167055e9c7e09 Mon Sep 17 00:00:00 2001 From: Andrey Novikov Date: Mon, 13 Jul 2015 16:56:55 +0300 Subject: [PATCH] Add autodetection and override of param key for `permitted_attributes` helper. First, trying to get param key for ActiveModel objects, as Rails' `form_for` helper uses it to generate key for parameters hash. See https://github.com/rails/rails/blob/9f44aa08636dfbba9261f4350ec14684425c4b7b/actionview/lib/action_view/helpers/form_helper.rb#L433 for reference. Second, allowing to redefine it with `param_key` option (as element in optional second argument hash), it is useful in case of single table inheritance, when the param key is differs from actual class (as it is getting defined at runtime). And last, use previous behaviour otherwise. Fixes https://github.com/elabs/pundit/issues/286 --- lib/pundit.rb | 11 +++++++++-- spec/pundit_spec.rb | 15 +++++++++++++++ spec/spec_helper.rb | 10 ++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/pundit.rb b/lib/pundit.rb index 610419f..865bc0f 100644 --- a/lib/pundit.rb +++ b/lib/pundit.rb @@ -139,8 +139,15 @@ module Pundit policies[record] ||= Pundit.policy!(pundit_user, record) end - def permitted_attributes(record) - name = record.class.to_s.demodulize.underscore + def permitted_attributes(record, options={}) + name = options.delete(:param_key) + name ||= if record.class.respond_to?(:model_name) # ActiveModel and ActiveRecord + record.class.model_name.param_key + elsif record.respond_to?(:model_name) + record.model_name.param_key + else + record.class.to_s.demodulize.underscore + end params.require(name).permit(policy(record).permitted_attributes) end diff --git a/spec/pundit_spec.rb b/spec/pundit_spec.rb index 7de6fbf..c48e005 100644 --- a/spec/pundit_spec.rb +++ b/spec/pundit_spec.rb @@ -3,6 +3,7 @@ require "spec_helper" describe Pundit do let(:user) { double } let(:post) { Post.new(user) } + let(:customer_post) { Customer::Post.new(user) } let(:comment) { Comment.new } let(:article) { Article.new } let(:controller) { Controller.new(user, { :action => 'update' }) } @@ -343,6 +344,20 @@ describe Pundit do expect(Controller.new(user, params).permitted_attributes(post)).to eq({ 'title' => 'Hello', 'votes' => 5 }) expect(Controller.new(double, params).permitted_attributes(post)).to eq({ 'votes' => 5 }) end + + it "checks policy for permitted attributes for record of a ActiveModel type" do + params = ActionController::Parameters.new({ action: 'update', customer_post: { title: 'Hello', votes: 5, admin: true } }) + + expect(Controller.new(user, params).permitted_attributes(customer_post)).to eq({ 'title' => 'Hello', 'votes' => 5 }) + expect(Controller.new(double, params).permitted_attributes(customer_post)).to eq({ 'votes' => 5 }) + end + + it "checks policy for permitted attributes for record with manually specified param key" do + params = ActionController::Parameters.new({ action: 'update', custom_post: { title: 'Hello', votes: 5, admin: true } }) + + expect(Controller.new(user, params).permitted_attributes(post, param_key: 'custom_post')).to eq({ 'title' => 'Hello', 'votes' => 5 }) + expect(Controller.new(double, params).permitted_attributes(post, param_key: 'custom_post')).to eq({ 'votes' => 5 }) + end end describe "Pundit::NotAuthorizedError" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cdbf0dd..d5be5ae 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -56,6 +56,16 @@ class Post < Struct.new(:user) def inspect; "#"; end end +module Customer + class Post < Post + def self.model_name + OpenStruct.new(param_key: 'customer_post') + end + def policy_class + PostPolicy + end + end +end class CommentPolicy < Struct.new(:user, :comment); end class CommentPolicy::Scope < Struct.new(:user, :scope) def resolve