Last active
December 22, 2015 20:18
-
-
Save DonSchado/6525126 to your computer and use it in GitHub Desktop.
Thoughtbot retracted their initial implementation of strong parameters matchers in v2.0.0 of shoulda-matchers, so we decided to build our own until new official ones are released. The following is a small matcher for testing what params should be permitted in controllers. The matcher's syntax is based on validation matchers. If you're not follow…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# assuming your subject is the UsersController with a method user_params | |
describe UsersController do | |
describe "params" do | |
# per default the matcher extracts the subject and params method | |
it { should permit_params(:email, :name, :role) } | |
# to overwrite the params method use explicit .params_method() | |
it { should permit_params(:first_name, :last_name).params_method(:other_user_params) } | |
# to overwrite the class use explicit .for_class() | |
it { should permit_params(:email, :name).for_class(SpecialUser) } | |
# overwrite both | |
it { should permit_params(:name).params_method(:my_params_method).for_class(SuperUser) } | |
# or use the expect syntax if you like | |
it { expect(permit_params(:email, :name)).to be_true } | |
# and since it's RSpec you can also use specify if you like | |
specify { expect(permit_params(:role).for_class(User).to be_false } | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module StrongParameterMatcher | |
class PermitMatcher | |
attr_reader :permitted_params, :errors_protected, :errors_permitted | |
def initialize(permitted_params) | |
@permitted_params = permitted_params | |
@errors_protected = [] | |
@errors_permitted = [] | |
end | |
def for_class(klass) | |
@klass_name = klass.name | |
@model = klass | |
self | |
end | |
def params_method(name) | |
@params_method = name | |
self | |
end | |
def matches?(controller) | |
default_klass_name(controller) | |
default_model | |
default_params_method | |
protected_params.each do |param| | |
controller.params = action_controller_parameters(param) | |
errors_protected << param if controller.send(@params_method)[param.to_sym] | |
end | |
permitted_params.each do |param| | |
controller.params = action_controller_parameters(param) | |
errors_permitted << param unless controller.send(@params_method).has_key?(param) | |
end | |
return errors_protected.empty? && errors_permitted.empty? | |
end | |
def failure_message | |
msg = "expected " | |
if !errors_protected.empty? | |
msg << "#{errors_protected} to be protected but is permitted" | |
else | |
msg << "#{errors_permitted} to be permitted but is not" | |
end | |
end | |
def description | |
"permit #{permitted_params} through :#{@params_method}" | |
end | |
private | |
def protected_params | |
@model.column_names - permitted_params.map(&:to_s) | |
end | |
def action_controller_parameters(param) | |
ActionController::Parameters.new(@klass_name.underscore.to_sym => {param => "random"}) | |
end | |
def default_klass_name(controller) | |
@klass_name ||= controller.class.name.gsub("Controller", "").classify | |
end | |
def default_model | |
@model ||= @klass_name.constantize | |
end | |
def default_params_method | |
@params_method ||= "#{@klass_name.underscore}_params".to_sym | |
end | |
end | |
def permit_params(*keys) | |
PermitMatcher.new(keys) | |
end | |
end | |
RSpec.configure do |config| | |
config.include(StrongParameterMatcher) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment