├── .coveralls.yml
├── lib
├── action_parameter
│ ├── version.rb
│ ├── railtie.rb
│ ├── helpers.rb
│ └── base.rb
├── generators
│ └── parameters
│ │ ├── templates
│ │ └── parameter_class.rb
│ │ ├── USAGE
│ │ └── parameters_generator.rb
└── action_parameter.rb
├── .gitignore
├── Gemfile
├── .travis.yml
├── CHANGELOG.md
├── Rakefile
├── test
├── test_helper.rb
└── action_parameter_test.rb
├── action_parameter.gemspec
├── MIT-LICENSE
└── README.md
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | service_name: travis-ci
2 | repo_token: UyOEGDlk0CRMGA13fGDYwg96fLKh1hOXs
--------------------------------------------------------------------------------
/lib/action_parameter/version.rb:
--------------------------------------------------------------------------------
1 | module ActionParameter
2 | VERSION = "0.0.3".freeze
3 | end
--------------------------------------------------------------------------------
/lib/generators/parameters/templates/parameter_class.rb:
--------------------------------------------------------------------------------
1 | class <%= name.camelcase %>Parameters < ActionParameter::Base
2 |
3 | end
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.bundle
2 | *.gem
3 | .bundle
4 | .idea
5 | Gemfile.lock
6 | log/*
7 | pkg/*
8 | .ruby-gemset
9 | .ruby-version
10 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec
4 |
5 | gem 'mocha', '~> 0.13.2', require: false
6 | gem 'rake'
7 | gem 'coveralls', require: false
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | script: "bundle exec rake test"
3 | rvm:
4 | - 1.9.3
5 | - 2.0.0
6 | gemfile:
7 | - Gemfile
8 | notifications:
9 | email: false
--------------------------------------------------------------------------------
/lib/generators/parameters/USAGE:
--------------------------------------------------------------------------------
1 | Description:
2 | Explain the generator
3 |
4 | Example:
5 | rails generate parameters Thing
6 |
7 | This will create:
8 | what/will/it/create
9 |
--------------------------------------------------------------------------------
/lib/action_parameter.rb:
--------------------------------------------------------------------------------
1 | require 'action_pack'
2 | require 'active_support'
3 | require 'action_parameter/railtie' if defined?(Rails)
4 |
5 | module ActionParameter
6 | extend ActiveSupport::Autoload
7 |
8 | autoload :Base, 'action_parameter/base.rb'
9 | autoload :Helpers, 'action_parameter/helpers.rb'
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/lib/action_parameter/railtie.rb:
--------------------------------------------------------------------------------
1 | require 'rails/railtie'
2 |
3 | module ActionParameter
4 | class Railtie < Rails::Railtie
5 |
6 | initializer "action_parameter.helpers" do |app|
7 | ActiveSupport.on_load :action_controller do
8 | include ActionParameter::Helpers
9 | end
10 | end
11 |
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/generators/parameters/parameters_generator.rb:
--------------------------------------------------------------------------------
1 | require 'rails/generators'
2 | require 'rails/generators/named_base'
3 |
4 | class ParametersGenerator < Rails::Generators::NamedBase
5 | source_root File.expand_path('../templates', __FILE__)
6 |
7 | def parameters
8 | template "parameter_class.rb", "app/parameters/#{name.underscore}_parameters.rb"
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### 0.0.3
2 |
3 | * bug fixing
4 | * Adds class namespacing support when guessing parameter class. Thanks to @poporul.
5 |
6 | ### 0.0.2
7 |
8 | * enhancements
9 | * Adds `locals` method to permitted_params to create helpers methods on ActionParameter
10 |
11 | * deprecations
12 | * `permitted_params(locals: {})` in favor of `permitted_params.locals({})`
13 | * `rails g parameter` rails' generator in favor of `rails g parameters`
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env rake
2 | begin
3 | require 'bundler/setup'
4 | require 'bundler/gem_tasks'
5 | rescue LoadError
6 | raise 'You must `gem install bundler` and `bundle install` to run rake tasks'
7 | end
8 |
9 | require 'rdoc/task'
10 |
11 | RDoc::Task.new(:rdoc) do |rdoc|
12 | rdoc.rdoc_dir = 'rdoc'
13 | rdoc.title = 'ActionParameter'
14 | rdoc.options << '--line-numbers'
15 | rdoc_main = 'README.md'
16 | rdoc.rdoc_files.include('README.md')
17 | rdoc.rdoc_files.include('lib/**/*.rb')
18 | end
19 |
20 | require 'rake/testtask'
21 |
22 | Rake::TestTask.new(:test) do |t|
23 | t.libs << 'lib'
24 | t.libs << 'test'
25 | t.pattern = 'test/**/*_test.rb'
26 | t.verbose = false
27 | end
28 |
29 | task :default => :test
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | require 'coveralls'
2 | Coveralls.wear!
3 |
4 | require 'bundler'
5 |
6 | Bundler.setup
7 | require 'test/unit'
8 | require 'mocha/setup'
9 |
10 | # Configure Rails
11 | ENV["RAILS_ENV"] = "test"
12 |
13 | require 'active_support'
14 | require 'action_controller'
15 | require 'action_dispatch/middleware/flash'
16 |
17 | $:.unshift File.expand_path('../../lib', __FILE__)
18 | require 'action_parameter'
19 |
20 | ActionParameter::Routes = ActionDispatch::Routing::RouteSet.new
21 | ActionParameter::Routes.draw do
22 | get '/:controller(/:action(/:id))'
23 | end
24 |
25 | class ApplicationController < ActionController::Base
26 | include ActionParameter::Routes.url_helpers
27 | end
28 |
29 | class ActiveSupport::TestCase
30 | setup do
31 | @routes = ActionParameter::Routes
32 | end
33 | end
--------------------------------------------------------------------------------
/action_parameter.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | $:.push File.expand_path("../lib", __FILE__)
3 | require "action_parameter/version"
4 |
5 | Gem::Specification.new do |s|
6 | s.name = "action_parameter"
7 | s.version = ActionParameter::VERSION.dup
8 | s.platform = Gem::Platform::RUBY
9 | s.summary = "Single Responsability Principle for Rails Controller's Parameters."
10 | s.email = "edelpero@gmail.com"
11 | s.homepage = "https://github.com/edelpero/action_parameter"
12 | s.description = "ActionParameter helps you move all your parameter's logic into it's own class. This way you'll keep your controllers dry and they would be easier to test."
13 | s.authors = ['Ezequiel Delpero']
14 | s.license = "MIT"
15 |
16 | s.files = `git ls-files`.split("\n")
17 | s.test_files = `git ls-files -- test/*`.split("\n")
18 | s.require_paths = ["lib"]
19 |
20 | s.add_development_dependency('minitest', '~> 4.2')
21 |
22 | s.add_dependency('activesupport', '>= 3.0.0')
23 | s.add_dependency('actionpack', '>= 3.0.0')
24 | end
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2009-2013 Ezequiel Delpero. http://github.com/edelpero
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/lib/action_parameter/helpers.rb:
--------------------------------------------------------------------------------
1 | module ActionParameter
2 | module Helpers
3 |
4 | protected
5 |
6 | # permitted_params: Returns an ActionParameter instance.
7 | #
8 | # == Options
9 | #
10 | # * options - Hash with one valid key: class.
11 | # * options[:class] - Symbol value with the name of the Parameters class you want to use.
12 | #
13 | # == Examples
14 | #
15 | # permitted_params(class: customer) # called from UsersController
16 | #
17 | # This will create an instance of CustomerParameters and also will make
18 | # 'params', 'controller_name' and 'action_name' helper methods
19 | # available on the CustomerParameters instace.
20 | def permitted_params(options = {})
21 | parameter_class = permitted_params_class(options[:class])
22 | @permitted_params ||= parameter_class.new(params)
23 | end
24 |
25 | # permitted_params_class: Returns a Parameters class.
26 | #
27 | # == Options
28 | #
29 | # * class_name - Symbol value with the name of the Parameters class you want to use.
30 | #
31 | # == Examples
32 | #
33 | # permitted_params_class(:customer) # called from PeopleController
34 | # # => CustomerParameters
35 | #
36 | # permitted_params_class(:customers) # called from PeopleController
37 | # # => CustomersParameters
38 | #
39 | # permitted_params_class() # called from PeopleController
40 | # # => PersonParameters
41 | def permitted_params_class(class_name = nil)
42 | class_name = class_name || self.class.name.sub(/Controller$/, '').singularize
43 | @permitted_params_class ||= "#{class_name.to_s.camelcase}Parameters".constantize
44 | end
45 |
46 | end
47 | end
--------------------------------------------------------------------------------
/lib/action_parameter/base.rb:
--------------------------------------------------------------------------------
1 | module ActionParameter
2 | class Base
3 |
4 | attr_accessor :params
5 |
6 | # initialize: Initialize parameter class and creates controller_name and action_name helpers.
7 | #
8 | # == Options
9 | #
10 | # * params - The ActionController::Parameters instance from the controller who initialize this.
11 | def initialize(params)
12 | @params = params
13 | create_base_helpers
14 | end
15 |
16 | # locals: Creates helper methods for the ActionParameter instace.
17 | #
18 | # == Options
19 | #
20 | # * locals - Hash used to create helper methods available for the ActionParameter instance.
21 | #
22 | # == Examples
23 | #
24 | # * locals(new_method: @value, another_method: @other_value)
25 | # # => 'ActionParameter instace'
26 | #
27 | # Returns the ActionParameter instace.
28 | def locals(locals = {})
29 | create_methods(locals)
30 | self
31 | end
32 |
33 | protected
34 |
35 | # create_base_helpers: Creates controller_name and action_name helper methods, every time an ActionParameter instace is created.
36 | def create_base_helpers
37 | locals = { controller_name: params[:controller],
38 | action_name: params[:action] }
39 | create_methods(locals)
40 | end
41 |
42 | # create_methods: Creates instance methods using locals hash's keys and values.
43 | #
44 | # == Options
45 | #
46 | # * locals - Hash used to create helper methods available for the ActionParameter instance. Methods will be named using the hash keys and they'll return the hash values.
47 | #
48 | # == Examples
49 | #
50 | # create_methods(current_user: @user, another_key: @another_variable)
51 | #
52 | # Will create 'current_user' and 'another_key' instance methods.
53 | # This methods will be aviable only in the current parameter class where create_method was called.
54 | # 'current_user' will return @user.
55 | # 'another_key' will return @another_variable
56 | def create_methods(locals = {})
57 | locals = {} unless locals
58 |
59 | klass = class << self; self; end
60 |
61 | locals.each do |method_name, value|
62 | klass.send(:define_method, method_name) do
63 | value
64 | end
65 | end
66 | end
67 |
68 | end
69 | end
--------------------------------------------------------------------------------
/test/action_parameter_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | UserParameters = Class.new(ActionParameter::Base)
4 | CustomerParameters = Class.new(ActionParameter::Base)
5 |
6 | Admin = Module.new
7 | Admin::UserParameters = Class.new(ActionParameter::Base)
8 | Admin::CustomerParameters = Class.new(ActionParameter::Base)
9 |
10 | module SharedActionMethods
11 | def permitted_params_without_arguments
12 | permitted_params
13 | render nothing: true
14 | end
15 |
16 | def permitted_params_with_class_attribute
17 | permitted_params(class: :customer)
18 | render nothing: true
19 | end
20 |
21 | def permitted_params_with_namespaced_class_attribute
22 | permitted_params(class: 'admin/customer')
23 | render nothing: true
24 | end
25 |
26 | def permitted_params_with_locals
27 | permitted_params.locals(current_user: 'user')
28 | render nothing: true
29 | end
30 | end
31 |
32 | class Admin::UsersController < ApplicationController
33 | include ActionParameter::Helpers
34 | include SharedActionMethods
35 | end
36 |
37 | class UsersController < ApplicationController
38 | include ActionParameter::Helpers
39 | include SharedActionMethods
40 | end
41 |
42 | class ActionParameterTest < ActionController::TestCase
43 | tests UsersController
44 |
45 | def test_permitted_params_without_arguments_is_an_instance_of_user_parameters
46 | get :permitted_params_without_arguments
47 | assert_equal('UserParameters', assigns(:permitted_params).class.to_s)
48 | end
49 |
50 | def test_permitted_params_with_class_attribute_returns_an_instance_of_customer_parameters
51 | get :permitted_params_with_class_attribute
52 | assert_equal('CustomerParameters', assigns(:permitted_params).class.to_s)
53 | end
54 |
55 | def test_permitted_params_instance_params_helper_method
56 | get :permitted_params_without_arguments
57 | assert_equal(@request.params, assigns(:permitted_params).params)
58 | end
59 |
60 | def test_permitted_params_instance_controller_name_helper_method
61 | get :permitted_params_without_arguments
62 | assert_equal(@request.params['controller'], assigns(:permitted_params).controller_name)
63 | end
64 |
65 | def test_permitted_params_instance_action_name_helper_method
66 | get :permitted_params_without_arguments
67 | assert_equal(@request.params['action'], assigns(:permitted_params).action_name)
68 | end
69 |
70 | def test_permitted_params_with_locals_should_respond_to_current_user_method
71 | get :permitted_params_with_locals
72 | assert_equal(true, assigns(:permitted_params).respond_to?(:current_user))
73 | end
74 | end
75 |
76 | class ActionParameterNamespaceTest < ActionController::TestCase
77 | tests Admin::UsersController
78 |
79 | def test_permitted_params_without_arguments_is_an_instance_of_user_parameters
80 | get :permitted_params_without_arguments
81 | assert_equal('Admin::UserParameters', assigns(:permitted_params).class.to_s)
82 | end
83 |
84 | def test_permitted_params_with_class_attribute_returns_an_instance_of_customer_parameters
85 | get :permitted_params_with_class_attribute
86 | assert_equal('CustomerParameters', assigns(:permitted_params).class.to_s)
87 | end
88 |
89 | def test_permitted_params_with_namespaced_class_attribute_returns_an_instance_of_customer_parameters
90 | get :permitted_params_with_namespaced_class_attribute
91 | assert_equal('Admin::CustomerParameters', assigns(:permitted_params).class.to_s)
92 | end
93 | end
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](http://badge.fury.io/rb/action_parameter)
2 | [](https://travis-ci.org/edelpero/action_parameter)
3 | [](https://coveralls.io/r/edelpero/action_parameter)
4 | [](https://codeclimate.com/github/edelpero/action_parameter)
5 | [](https://bitdeli.com/free "Bitdeli Badge")
6 |
7 | ActionParameter
8 | ===============
9 |
10 | ActionParameter helps you move all your parameter's logic into it's own class. This way you'll keep your controllers dry and they would be easier to test.
11 |
12 | Before
13 | ------
14 |
15 | ```ruby
16 | # app/controllers/users_controllers.rb
17 | class UsersController < ActionController::Base
18 | def create
19 | User.create(user_params)
20 | end
21 |
22 | private
23 | def user_params
24 | params.require(:user).permit(:name, :age)
25 | end
26 | end
27 | ```
28 |
29 | After
30 | -----
31 |
32 | ```ruby
33 | # app/controllers/users_controllers.rb
34 | class UsersController < ActionController::Base
35 | def create
36 | # It automatically deduces which Parameters class from Controller's name
37 | User.create(permitted_params.permit)
38 | end
39 | end
40 | ```
41 |
42 | ```ruby
43 | # app/parameters/user_parameters.rb
44 | class UserParameters < ActionParameter::Base
45 | def permit
46 | params.require(:user).permit(:name, :age)
47 | end
48 | end
49 | ```
50 |
51 | Install
52 | -------
53 |
54 | ActionParameter works with Rails 3.0 onwards and Ruby 1.9.3 onwards. You can add it to your Gemfile with:
55 |
56 | ```ruby
57 | gem 'action_parameter'
58 | ```
59 |
60 | Run the bundle command to install it.
61 |
62 | Usage
63 | -----
64 |
65 | ####Generator
66 |
67 | ```ruby
68 | rails generate parameters [MODEL_NAME]
69 | ```
70 | Will create **app/parameters/[model_name]_parameters.rb**.
71 |
72 | ####Controller Helpers
73 |
74 | - **permitted_params:** Returns an ActionParameter instance.
75 |
76 | ```ruby
77 | permitted_params(options={})
78 | ```
79 |
80 | #####Options Hash
81 |
82 | * **options** - Hash with one valid key: **:class**.
83 | * **options[:class]** - Symbol value with the name of the Parameters class you want to use.
84 |
85 | #####Example 1
86 |
87 | ```ruby
88 | # app/controllers/people_controllers.rb
89 | class PeopleController < ActionController::Base
90 | def create
91 | Person.create(permitted_params.permit) # This will call to PersonParameters' permit method
92 | end
93 | end
94 | ```
95 |
96 | ```ruby
97 | # app/parameters/person_parameters.rb
98 | class PersonParameters < ActionParameter::Base
99 | def permit
100 | params.require(:person).permit(:name, :age)
101 | end
102 | end
103 | ```
104 |
105 | #####Example 2
106 |
107 | ```ruby
108 | # app/controllers/people_controllers.rb
109 | class PeopleController < ActionController::Base
110 | def create
111 | Person.create(permitted_params(class: :user).sign_up) # This will call to UserParameters' sign_up method
112 | end
113 | end
114 | ```
115 |
116 | ```ruby
117 | # app/parameters/user_parameters.rb
118 | class UserParameters < ActionParameter::Base
119 | def sign_up
120 | params.require(:person).permit(:name, :age)
121 | end
122 | end
123 | ```
124 |
125 | ####Parameter Class Helpers
126 |
127 | #####Default Helpers
128 |
129 | - **params:** Returns params from the current controller request which instantiated the Parameter class.
130 | - **controller_name:** Returns the controller's name from which the Parameter class was instantiated.
131 | - **action_name:** Returns the action's name from the controller from which the Parameter class was instantiated.
132 |
133 | #####Creating New Helpers
134 |
135 | If you want to create new helper methods for your parameters class, just call **locals** method over **permitted_params**. Let say you want to make **@current_user** available for the UserParameter's class under the **user** method, then you'll need to use the **locals** method to tell the UserParameters class to create a new helper that returns **@current_user**.
136 |
137 | ```ruby
138 | permitted_params(class: :user).locals( user: @current_user,
139 | another_helper: @value )
140 | ```
141 | This will create **user** and **another_helper** methods and they will be available in UserParameters class.
142 |
143 | #####Example
144 |
145 | ```ruby
146 | # app/controllers/users_controllers.rb
147 | class UsersController < ActionController::Base
148 | def create
149 | User.create(permitted_params.locals(user: @current_user).permit) # This will call to UserParameters' permit method
150 | end
151 | end
152 | ```
153 |
154 | ```ruby
155 | # app/parameters/user_parameters.rb
156 | class UserParameters < ActionParameter::Base
157 | def permit
158 | if user.admin?
159 | params.require(:person).permit(:name, :age, :admin)
160 | else
161 | params.require(:person).permit(:name, :age)
162 | end
163 | end
164 | end
165 | ```
166 |
167 | RSpec
168 | -----
169 |
170 | This example shows how to test using RSpec.
171 |
172 | Theses tests require your **test.rb** configured to **config.action_controller.action_on_unpermitted_parameters = :raise**.
173 |
174 | ```ruby
175 | # spec/parameters/user_parameters_spec.rb
176 | require "spec_helper"
177 |
178 | describe UserParameters do
179 | describe ".permit" do
180 | describe "when permitted parameters" do
181 | it "returns the cleaned parameters" do
182 | user_params = { first_name: "John", last_name: "Doe" }
183 | params = ActionController::Parameters.new(user: user_params)
184 |
185 | permitted_params = UserParameters.new(params).permit
186 |
187 | expect(permitted_params).to eq user_params.with_indifferent_access
188 | end
189 | end
190 |
191 | describe "when unpermitted parameters" do
192 | it "raises error" do
193 | user_params = { foo: "bar" }
194 | params = ActionController::Parameters.new(user: user_params)
195 |
196 | expect{ UserParameters.new(params).permit }.
197 | to raise_error(ActionController::UnpermittedParameters)
198 | end
199 | end
200 | end
201 | end
202 |
203 | ```
204 |
205 |
--------------------------------------------------------------------------------