strongly_typed_parameters 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +90 -0
- data/Rakefile +28 -0
- data/lib/action_controller/parameters.rb +240 -0
- data/lib/active_model/forbidden_attributes_protection.rb +15 -0
- data/lib/generators/rails/USAGE +12 -0
- data/lib/generators/rails/strong_parameters_controller_generator.rb +17 -0
- data/lib/generators/rails/templates/controller.rb +94 -0
- data/lib/strongly_typed_parameters.rb +4 -0
- data/lib/strongly_typed_parameters/boolean.rb +12 -0
- data/lib/strongly_typed_parameters/railtie.rb +17 -0
- data/lib/strongly_typed_parameters/version.rb +3 -0
- data/test/action_controller_required_params_test.rb +30 -0
- data/test/action_controller_tainted_params_test.rb +25 -0
- data/test/active_model_mass_assignment_taint_protection_test.rb +30 -0
- data/test/active_model_smart_type_defaulting_test.rb +28 -0
- data/test/controller_generator_test.rb +38 -0
- data/test/gemfiles/Gemfile.rails-3.0.x +6 -0
- data/test/gemfiles/Gemfile.rails-3.0.x.lock +62 -0
- data/test/gemfiles/Gemfile.rails-3.1.x +6 -0
- data/test/gemfiles/Gemfile.rails-3.2.x +6 -0
- data/test/log_on_unpermitted_params_test.rb +50 -0
- data/test/multi_parameter_attributes_test.rb +38 -0
- data/test/parameters_permit_test.rb +264 -0
- data/test/parameters_require_test.rb +10 -0
- data/test/parameters_taint_test.rb +93 -0
- data/test/raise_on_unpermitted_params_test.rb +33 -0
- data/test/test_helper.rb +36 -0
- metadata +171 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 David Heinemeier Hansson
|
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.
|
data/README.rdoc
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
= Strong(ly typed) Parameters
|
2
|
+
|
3
|
+
With this plugin Action Controller parameters are forbidden to be used in Active Model mass assignments until they have been whitelisted. This means you'll have to make a conscious choice about which attributes to allow for mass updating and thus prevent accidentally exposing that which shouldn't be exposed.
|
4
|
+
In this fork, the type of each parameter is also validated to avoid unexpected behavior with implicit casting.
|
5
|
+
|
6
|
+
In addition, parameters can be marked as required and flow through a predefined raise/rescue flow to end up as a 400 Bad Request with no effort.
|
7
|
+
|
8
|
+
class PeopleController < ActionController::Base
|
9
|
+
# This will raise an ActiveModel::ForbiddenAttributes exception because it's using mass assignment
|
10
|
+
# without an explicit permit step.
|
11
|
+
def create
|
12
|
+
Person.create(params[:person])
|
13
|
+
end
|
14
|
+
|
15
|
+
# This will pass with flying colors as long as there's a person key in the parameters, otherwise
|
16
|
+
# it'll raise a ActionController::MissingParameter exception, which will get caught by
|
17
|
+
# ActionController::Base and turned into that 400 Bad Request reply.
|
18
|
+
def update
|
19
|
+
person = current_account.people.find(params[:id])
|
20
|
+
person.update_attributes!(person_params)
|
21
|
+
redirect_to person
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
# Using a private method to encapsulate the permissible parameters is just a good pattern
|
26
|
+
# since you'll be able to reuse the same permit list between create and update. Also, you
|
27
|
+
# can specialize this method with per-user checking of permissible attributes.
|
28
|
+
def person_params
|
29
|
+
params.require(:person).permit(:name, :age)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
== Permitted Types
|
34
|
+
|
35
|
+
Given
|
36
|
+
|
37
|
+
params.permit(:id)
|
38
|
+
|
39
|
+
the key +:id+ will pass the whitelisting if it appears in +params+ and is a String. Otherwise the key is going to be filtered out, so arrays, hashes, or any other objects cannot be injected.
|
40
|
+
|
41
|
+
If instead the argument is given as
|
42
|
+
|
43
|
+
params.permit(:id => Numeric)
|
44
|
+
|
45
|
+
the +:id+ value must be a number. Any class or module can be given here. The marker module Boolean is included in TrueClass and FalseClass.
|
46
|
+
|
47
|
+
To declare that the value in +params+ must be an array of values of a certain type, wrap the type constant in an Array:
|
48
|
+
|
49
|
+
params.permit(:id => [Numeric])
|
50
|
+
|
51
|
+
== Defaults with ActiveRecord
|
52
|
+
|
53
|
+
If a parameter shares a name with an ActiveRecord model, the default types for its attributes are those of that model, rather than String.
|
54
|
+
|
55
|
+
== Nested Parameters
|
56
|
+
|
57
|
+
You can also use permit on nested parameters, like:
|
58
|
+
|
59
|
+
params.permit(:name, {:emails => [String]}, :friends => [ :name, { :family => [ :name ] }])
|
60
|
+
|
61
|
+
Thanks to Nick Kallen for the permit idea!
|
62
|
+
|
63
|
+
== Handling of Unpermitted Keys
|
64
|
+
|
65
|
+
By default parameter keys that are not explicitly permitted will be logged in the development and test environment. In other environments these parameters will simply be filtered out and ignored.
|
66
|
+
|
67
|
+
Additionally, this behaviour can be changed by changing the +config.action_controller.action_on_unpermitted_parameters+ property in your environment files. If set to +:log+ the unpermitted attributes will be logged, if set to +:raise+ an exception will be raised.
|
68
|
+
|
69
|
+
== Installation
|
70
|
+
|
71
|
+
In Gemfile:
|
72
|
+
|
73
|
+
gem 'strongly_typed_parameters'
|
74
|
+
|
75
|
+
and then run `bundle`. To activate the strong parameters, you need to include this module in
|
76
|
+
every model you want protected.
|
77
|
+
|
78
|
+
class Post < ActiveRecord::Base
|
79
|
+
include ActiveModel::ForbiddenAttributesProtection
|
80
|
+
end
|
81
|
+
|
82
|
+
If you want to now disable the default whitelisting that occurs in later versions of Rails, change the +config.active_record.whitelist_attributes+ property in your +config/application.rb+:
|
83
|
+
|
84
|
+
config.active_record.whitelist_attributes = false
|
85
|
+
|
86
|
+
This will allow you to remove / not have to use +attr_accessible+ and do mass assignment inside your code and tests.
|
87
|
+
|
88
|
+
== Compatibility
|
89
|
+
|
90
|
+
This plugin is only fully compatible with Rails versions 3.0, 3.1 and 3.2 but not 4.0+, as the non-typechecking version is part of Rails Core in 4.0.
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
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 = 'StrongParameters'
|
14
|
+
rdoc.options << '--line-numbers'
|
15
|
+
rdoc.rdoc_files.include('README.rdoc')
|
16
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
|
21
|
+
Rake::TestTask.new(:test) do |t|
|
22
|
+
t.libs << 'lib'
|
23
|
+
t.libs << 'test'
|
24
|
+
t.pattern = 'test/**/*_test.rb'
|
25
|
+
t.verbose = false
|
26
|
+
end
|
27
|
+
|
28
|
+
task :default => :test
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
require 'active_support/concern'
|
6
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
7
|
+
require 'action_controller'
|
8
|
+
require 'action_dispatch/http/upload'
|
9
|
+
|
10
|
+
module ActionController
|
11
|
+
class ParameterMissing < IndexError
|
12
|
+
attr_reader :param
|
13
|
+
|
14
|
+
def initialize(param)
|
15
|
+
@param = param
|
16
|
+
super("key not found: #{param}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class UnpermittedParameters < IndexError
|
21
|
+
attr_reader :params
|
22
|
+
|
23
|
+
def initialize(params)
|
24
|
+
@params = params
|
25
|
+
super("found unpermitted parameters: #{params.join(", ")}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Parameters < ActiveSupport::HashWithIndifferentAccess
|
30
|
+
attr_accessor :permitted
|
31
|
+
alias :permitted? :permitted
|
32
|
+
attr_accessor :klass
|
33
|
+
|
34
|
+
cattr_accessor :action_on_unpermitted_parameters, :instance_accessor => false
|
35
|
+
|
36
|
+
# Never raise an UnpermittedParameters exception because of these params
|
37
|
+
# are present. They are added by Rails and it's of no concern.
|
38
|
+
NEVER_UNPERMITTED_PARAMS = %w( controller action )
|
39
|
+
|
40
|
+
def initialize(attributes = nil, klass = String)
|
41
|
+
super(attributes)
|
42
|
+
@permitted = false
|
43
|
+
@klass = klass
|
44
|
+
end
|
45
|
+
|
46
|
+
def permit!
|
47
|
+
each_pair do |key, value|
|
48
|
+
convert_hashes_to_parameters(key, value)
|
49
|
+
self[key].permit! if self[key].respond_to? :permit!
|
50
|
+
end
|
51
|
+
|
52
|
+
@permitted = true
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def require(key)
|
57
|
+
self[key].presence || raise(ActionController::ParameterMissing.new(key))
|
58
|
+
end
|
59
|
+
|
60
|
+
alias :required :require
|
61
|
+
|
62
|
+
def permit(*filters)
|
63
|
+
params = self.class.new
|
64
|
+
filters.each do |filter|
|
65
|
+
rule = filter.is_a?(Hash) ? filter : default_rule(filter)
|
66
|
+
if rule.values.one? && rule.values.first.is_a?(Class)
|
67
|
+
permitted_scalar_filter(params, rule.keys.first, rule.values.first)
|
68
|
+
else
|
69
|
+
apply_filter(params, rule)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters
|
74
|
+
|
75
|
+
params.permit!
|
76
|
+
end
|
77
|
+
|
78
|
+
def [](key)
|
79
|
+
convert_hashes_to_parameters(key, super)
|
80
|
+
end
|
81
|
+
|
82
|
+
def fetch(key, *args)
|
83
|
+
convert_hashes_to_parameters(key, super)
|
84
|
+
rescue KeyError, IndexError
|
85
|
+
raise ActionController::ParameterMissing.new(key)
|
86
|
+
end
|
87
|
+
|
88
|
+
def slice(*keys)
|
89
|
+
self.class.new(super).tap do |new_instance|
|
90
|
+
new_instance.instance_variable_set :@permitted, @permitted
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def dup
|
95
|
+
self.class.new(self).tap do |duplicate|
|
96
|
+
duplicate.default = default
|
97
|
+
duplicate.instance_variable_set :@permitted, @permitted
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
def convert_value(value)
|
103
|
+
if value.class == Hash
|
104
|
+
self.class.new_from_hash_copying_default(value)
|
105
|
+
elsif value.is_a?(Array)
|
106
|
+
value.dup.replace(value.map { |e| convert_value(e) })
|
107
|
+
else
|
108
|
+
value
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def convert_hashes_to_parameters(key, value)
|
115
|
+
if value.is_a?(Parameters) || !value.is_a?(Hash)
|
116
|
+
value
|
117
|
+
else
|
118
|
+
# Convert to Parameters on first access
|
119
|
+
self[key] = self.class.new(value)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def permitted_scalar?(value, klass)
|
124
|
+
value.is_a?(klass)
|
125
|
+
end
|
126
|
+
|
127
|
+
def array_of_permitted_scalars?(value,klass)
|
128
|
+
if value.is_a?(Array)
|
129
|
+
value.all? {|element| permitted_scalar?(element,klass)}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def permitted_scalar_filter(params, key, klass)
|
134
|
+
if has_key?(key) && permitted_scalar?(self[key],klass)
|
135
|
+
params[key] = self[key]
|
136
|
+
end
|
137
|
+
|
138
|
+
keys.grep(/\A#{Regexp.escape(key.to_s)}\(\d+[if]?\)\z/).each do |key|
|
139
|
+
if permitted_scalar?(self[key],klass)
|
140
|
+
params[key] = self[key]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def array_of_permitted_scalars_filter(params, key, rule)
|
146
|
+
raise ArgumentError unless rule.one?
|
147
|
+
if has_key?(key) && array_of_permitted_scalars?(self[key],rule.first)
|
148
|
+
params[key] = self[key]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def apply_filter(params, filter)
|
153
|
+
filter = filter.with_indifferent_access
|
154
|
+
|
155
|
+
# Slicing filters out non-declared keys.
|
156
|
+
slice(*filter.keys).each do |key, value|
|
157
|
+
|
158
|
+
rule = filter[key]
|
159
|
+
|
160
|
+
# Declaration {:favorite_numbers => [Numeric]}
|
161
|
+
if rule.is_a?(Array) && rule.first.is_a?(Class)
|
162
|
+
array_of_permitted_scalars_filter(params, key, rule)
|
163
|
+
# Declaration {:favorite_number => Numeric} or :uuid [=> String]
|
164
|
+
elsif rule.is_a?(Class) || rule.is_a?(Module)
|
165
|
+
permitted_scalar_filter(params, key, rule)
|
166
|
+
else
|
167
|
+
# Declaration {:user => :name} or {:user => [:name, :age, {:address => ...}]}
|
168
|
+
raise ArgumentError if rule.empty?
|
169
|
+
params[key] = each_element(value) do |element|
|
170
|
+
if element.is_a?(Hash)
|
171
|
+
element = self.class.new(element) unless element.respond_to?(:permit)
|
172
|
+
element.klass = key.camelize.constantize rescue String
|
173
|
+
element.permit(*Array.wrap(rule))
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def default_rule(filter)
|
181
|
+
if @klass.respond_to?(:columns) && (type = @klass.columns.find { |attr| attr.name == filter.to_s })
|
182
|
+
{filter => type.klass}
|
183
|
+
else
|
184
|
+
{filter => String}
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def each_element(value)
|
189
|
+
if value.is_a?(Array)
|
190
|
+
value.map { |el| yield el }.compact
|
191
|
+
# fields_for on an array of records uses numeric hash keys.
|
192
|
+
elsif value.is_a?(Hash) && value.keys.all? { |k| k =~ /\A-?\d+\z/ }
|
193
|
+
hash = value.class.new
|
194
|
+
value.each { |k,v| hash[k] = yield v }
|
195
|
+
hash
|
196
|
+
else
|
197
|
+
yield value
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def unpermitted_parameters!(params)
|
202
|
+
return unless self.class.action_on_unpermitted_parameters
|
203
|
+
|
204
|
+
unpermitted_keys = unpermitted_keys(params)
|
205
|
+
|
206
|
+
if unpermitted_keys.any?
|
207
|
+
case self.class.action_on_unpermitted_parameters
|
208
|
+
when :log
|
209
|
+
ActionController::Base.logger.debug "Unpermitted parameters: #{unpermitted_keys.join(", ")}"
|
210
|
+
when :raise
|
211
|
+
raise ActionController::UnpermittedParameters.new(unpermitted_keys)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def unpermitted_keys(params)
|
217
|
+
self.keys - params.keys - NEVER_UNPERMITTED_PARAMS
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
module StrongParameters
|
222
|
+
extend ActiveSupport::Concern
|
223
|
+
|
224
|
+
included do
|
225
|
+
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
|
226
|
+
render :text => "Required parameter missing: #{parameter_missing_exception.param}", :status => :bad_request
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def params
|
231
|
+
@_params ||= Parameters.new(request.parameters)
|
232
|
+
end
|
233
|
+
|
234
|
+
def params=(val)
|
235
|
+
@_params = val.is_a?(Hash) ? Parameters.new(val) : val
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
ActionController::Base.send :include, ActionController::StrongParameters
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
class ForbiddenAttributes < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
module ForbiddenAttributesProtection
|
6
|
+
def sanitize_for_mass_assignment(*options)
|
7
|
+
new_attributes = options.first
|
8
|
+
if !new_attributes.respond_to?(:permitted?) || new_attributes.permitted?
|
9
|
+
super
|
10
|
+
else
|
11
|
+
raise ActiveModel::ForbiddenAttributes
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Description:
|
2
|
+
Stubs out a scaffolded controller and its views. Different from rails
|
3
|
+
scaffold_controller, it uses strongly_typed_parameters to whitelist permissible
|
4
|
+
attributes in a private method.
|
5
|
+
Pass the model name, either CamelCased or under_scored. The controller
|
6
|
+
name is retrieved as a pluralized version of the model name.
|
7
|
+
|
8
|
+
To create a controller within a module, specify the model name as a
|
9
|
+
path like 'parent_module/controller_name'.
|
10
|
+
|
11
|
+
This generates a controller class in app/controllers and invokes helper,
|
12
|
+
template engine and test framework generators.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rails/version'
|
2
|
+
require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
module Generators
|
6
|
+
class StrongParametersControllerGenerator < ScaffoldControllerGenerator
|
7
|
+
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
|
8
|
+
source_root File.expand_path("../templates", __FILE__)
|
9
|
+
|
10
|
+
if ::Rails::VERSION::STRING < '3.1'
|
11
|
+
def module_namespacing
|
12
|
+
yield if block_given?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
<% module_namespacing do -%>
|
2
|
+
class <%= controller_class_name %>Controller < ApplicationController
|
3
|
+
# GET <%= route_url %>
|
4
|
+
# GET <%= route_url %>.json
|
5
|
+
def index
|
6
|
+
@<%= plural_table_name %> = <%= orm_class.all(class_name) %>
|
7
|
+
|
8
|
+
respond_to do |format|
|
9
|
+
format.html # index.html.erb
|
10
|
+
format.json { render json: <%= "@#{plural_table_name}" %> }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# GET <%= route_url %>/1
|
15
|
+
# GET <%= route_url %>/1.json
|
16
|
+
def show
|
17
|
+
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
18
|
+
|
19
|
+
respond_to do |format|
|
20
|
+
format.html # show.html.erb
|
21
|
+
format.json { render json: <%= "@#{singular_table_name}" %> }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# GET <%= route_url %>/new
|
26
|
+
# GET <%= route_url %>/new.json
|
27
|
+
def new
|
28
|
+
@<%= singular_table_name %> = <%= orm_class.build(class_name) %>
|
29
|
+
|
30
|
+
respond_to do |format|
|
31
|
+
format.html # new.html.erb
|
32
|
+
format.json { render json: <%= "@#{singular_table_name}" %> }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# GET <%= route_url %>/1/edit
|
37
|
+
def edit
|
38
|
+
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
39
|
+
end
|
40
|
+
|
41
|
+
# POST <%= route_url %>
|
42
|
+
# POST <%= route_url %>.json
|
43
|
+
def create
|
44
|
+
@<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
|
45
|
+
|
46
|
+
respond_to do |format|
|
47
|
+
if @<%= orm_instance.save %>
|
48
|
+
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> }
|
49
|
+
format.json { render json: <%= "@#{singular_table_name}" %>, status: :created, location: <%= "@#{singular_table_name}" %> }
|
50
|
+
else
|
51
|
+
format.html { render action: "new" }
|
52
|
+
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# PATCH/PUT <%= route_url %>/1
|
58
|
+
# PATCH/PUT <%= route_url %>/1.json
|
59
|
+
def update
|
60
|
+
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
61
|
+
|
62
|
+
respond_to do |format|
|
63
|
+
if @<%= orm_instance.update_attributes("#{singular_table_name}_params") %>
|
64
|
+
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> }
|
65
|
+
format.json { head :no_content }
|
66
|
+
else
|
67
|
+
format.html { render action: "edit" }
|
68
|
+
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# DELETE <%= route_url %>/1
|
74
|
+
# DELETE <%= route_url %>/1.json
|
75
|
+
def destroy
|
76
|
+
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
77
|
+
@<%= orm_instance.destroy %>
|
78
|
+
|
79
|
+
respond_to do |format|
|
80
|
+
format.html { redirect_to <%= index_helper %>_url }
|
81
|
+
format.json { head :no_content }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Use this method to whitelist the permissible parameters. Example:
|
88
|
+
# params.require(:person).permit(:name, :age)
|
89
|
+
# Also, you can specialize this method with per-user checking of permissible attributes.
|
90
|
+
def <%= "#{singular_table_name}_params" %>
|
91
|
+
params.require(<%= ":#{singular_table_name}" %>).permit(<%= attributes.map {|a| ":#{a.name}" }.sort.join(', ') %>)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
<% end -%>
|