protected_attributes 1.0.9 → 1.1.0
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.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/lib/active_model/mass_assignment_security.rb +9 -0
- data/lib/protected_attributes/version.rb +1 -1
- metadata +3 -49
- data/test/abstract_unit.rb +0 -165
- data/test/accessible_params_wrapper_test.rb +0 -76
- data/test/ar_helper.rb +0 -74
- data/test/attribute_sanitization_test.rb +0 -1077
- data/test/mass_assignment_security/black_list_test.rb +0 -21
- data/test/mass_assignment_security/permission_set_test.rb +0 -37
- data/test/mass_assignment_security/sanitizer_test.rb +0 -51
- data/test/mass_assignment_security/white_list_test.rb +0 -20
- data/test/mass_assignment_security_test.rb +0 -118
- data/test/models/battle.rb +0 -5
- data/test/models/company.rb +0 -17
- data/test/models/group.rb +0 -6
- data/test/models/keyboard.rb +0 -3
- data/test/models/mass_assignment_specific.rb +0 -76
- data/test/models/membership.rb +0 -8
- data/test/models/person.rb +0 -46
- data/test/models/pirate.rb +0 -5
- data/test/models/subscriber.rb +0 -5
- data/test/models/task.rb +0 -5
- data/test/models/team.rb +0 -5
- data/test/models/vampire.rb +0 -4
- data/test/models/wolf.rb +0 -4
- data/test/test_helper.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 395ab272536df136e316a89087b094b773f6be7b
|
4
|
+
data.tar.gz: 279387fed8cec2a444b8a279c64d78aa6c3d876e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a034a1aae746c4d3c942e96d8201010fc5654ae4487547b64a67fee0f2e907321978d6af68050b34fc033e01598d2e579b661e03ae4f5d19d20253f7d3316db8
|
7
|
+
data.tar.gz: d114248044437b7da5d9760d07468b9d4670aeaff2654c0042d3f76e1c16fa1305016d8d5680402351a72dd17b6e067ede82e3696614f22021d54fcc532d792f
|
data/README.md
CHANGED
@@ -75,13 +75,13 @@ In a similar way, `new`, `create`, `create!`, `update_attributes` and `update_at
|
|
75
75
|
@user.name # => Sebastian
|
76
76
|
@user.is_admin # => true
|
77
77
|
```
|
78
|
-
|
79
|
-
This
|
78
|
+
By default the gem will create an empty whitelist of attributes available for mass-assignment for all models in your app.
|
79
|
+
As such, your models will need to explicitly whitelist or blacklist accessible parameters by using an `attr_accessible` or `attr_protected` declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to use this application config option; run your tests, and expose each attribute (via `attr_accessible` or `attr_protected`), as dictated by your failing test.
|
80
|
+
|
81
|
+
This option can be turned off using a configuration option:
|
80
82
|
```ruby
|
81
|
-
config.active_record.whitelist_attributes =
|
83
|
+
config.active_record.whitelist_attributes = false
|
82
84
|
```
|
83
|
-
This will create an empty whitelist of attributes available for mass-assignment for all models in your app.
|
84
|
-
As such, your models will need to explicitly whitelist or blacklist accessible parameters by using an `attr_accessible` or `attr_protected` declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to use this application config option; run your tests, and expose each attribute (via `attr_accessible` or `attr_protected`), as dictated by your failing test.
|
85
85
|
|
86
86
|
For more complex permissions, mass-assignment security may be handled outside the model by extending a non-ActiveRecord class, such as a controller, with this behavior.
|
87
87
|
|
@@ -50,11 +50,14 @@ module ActiveModel
|
|
50
50
|
# example implementation.
|
51
51
|
module MassAssignmentSecurity
|
52
52
|
extend ActiveSupport::Concern
|
53
|
+
include ActiveModel::ForbiddenAttributesProtection
|
53
54
|
|
54
55
|
included do
|
55
56
|
class_attribute :_accessible_attributes, instance_writer: false
|
56
57
|
class_attribute :_protected_attributes, instance_writer: false
|
57
58
|
class_attribute :_active_authorizer, instance_writer: false
|
59
|
+
class_attribute :_uses_mass_assignment_security, instance_writer: false
|
60
|
+
self._uses_mass_assignment_security = false
|
58
61
|
|
59
62
|
class_attribute :_mass_assignment_sanitizer, instance_writer: false
|
60
63
|
self.mass_assignment_sanitizer = :logger
|
@@ -123,6 +126,7 @@ module ActiveModel
|
|
123
126
|
self._protected_attributes[name] = self.protected_attributes(name) + args
|
124
127
|
end
|
125
128
|
|
129
|
+
self._uses_mass_assignment_security = true
|
126
130
|
self._active_authorizer = self._protected_attributes
|
127
131
|
end
|
128
132
|
|
@@ -189,6 +193,7 @@ module ActiveModel
|
|
189
193
|
self._accessible_attributes[name] = self.accessible_attributes(name) + args
|
190
194
|
end
|
191
195
|
|
196
|
+
self._uses_mass_assignment_security = true
|
192
197
|
self._active_authorizer = self._accessible_attributes
|
193
198
|
end
|
194
199
|
|
@@ -343,6 +348,10 @@ module ActiveModel
|
|
343
348
|
protected
|
344
349
|
|
345
350
|
def sanitize_for_mass_assignment(attributes, role = nil) #:nodoc:
|
351
|
+
unless _uses_mass_assignment_security
|
352
|
+
sanitize_forbidden_attributes(attributes)
|
353
|
+
end
|
354
|
+
|
346
355
|
_mass_assignment_sanitizer.sanitize(self.class, attributes, mass_assignment_authorizer(role))
|
347
356
|
end
|
348
357
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protected_attributes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -144,29 +144,6 @@ files:
|
|
144
144
|
- lib/protected_attributes.rb
|
145
145
|
- lib/protected_attributes/railtie.rb
|
146
146
|
- lib/protected_attributes/version.rb
|
147
|
-
- test/abstract_unit.rb
|
148
|
-
- test/accessible_params_wrapper_test.rb
|
149
|
-
- test/ar_helper.rb
|
150
|
-
- test/attribute_sanitization_test.rb
|
151
|
-
- test/mass_assignment_security/black_list_test.rb
|
152
|
-
- test/mass_assignment_security/permission_set_test.rb
|
153
|
-
- test/mass_assignment_security/sanitizer_test.rb
|
154
|
-
- test/mass_assignment_security/white_list_test.rb
|
155
|
-
- test/mass_assignment_security_test.rb
|
156
|
-
- test/models/battle.rb
|
157
|
-
- test/models/company.rb
|
158
|
-
- test/models/group.rb
|
159
|
-
- test/models/keyboard.rb
|
160
|
-
- test/models/mass_assignment_specific.rb
|
161
|
-
- test/models/membership.rb
|
162
|
-
- test/models/person.rb
|
163
|
-
- test/models/pirate.rb
|
164
|
-
- test/models/subscriber.rb
|
165
|
-
- test/models/task.rb
|
166
|
-
- test/models/team.rb
|
167
|
-
- test/models/vampire.rb
|
168
|
-
- test/models/wolf.rb
|
169
|
-
- test/test_helper.rb
|
170
147
|
homepage: https://github.com/rails/protected_attributes
|
171
148
|
licenses:
|
172
149
|
- MIT
|
@@ -191,27 +168,4 @@ rubygems_version: 2.4.5
|
|
191
168
|
signing_key:
|
192
169
|
specification_version: 4
|
193
170
|
summary: Protect attributes from mass assignment in Active Record models
|
194
|
-
test_files:
|
195
|
-
- test/abstract_unit.rb
|
196
|
-
- test/accessible_params_wrapper_test.rb
|
197
|
-
- test/ar_helper.rb
|
198
|
-
- test/attribute_sanitization_test.rb
|
199
|
-
- test/mass_assignment_security/black_list_test.rb
|
200
|
-
- test/mass_assignment_security/permission_set_test.rb
|
201
|
-
- test/mass_assignment_security/sanitizer_test.rb
|
202
|
-
- test/mass_assignment_security/white_list_test.rb
|
203
|
-
- test/mass_assignment_security_test.rb
|
204
|
-
- test/models/battle.rb
|
205
|
-
- test/models/company.rb
|
206
|
-
- test/models/group.rb
|
207
|
-
- test/models/keyboard.rb
|
208
|
-
- test/models/mass_assignment_specific.rb
|
209
|
-
- test/models/membership.rb
|
210
|
-
- test/models/person.rb
|
211
|
-
- test/models/pirate.rb
|
212
|
-
- test/models/subscriber.rb
|
213
|
-
- test/models/task.rb
|
214
|
-
- test/models/team.rb
|
215
|
-
- test/models/vampire.rb
|
216
|
-
- test/models/wolf.rb
|
217
|
-
- test/test_helper.rb
|
171
|
+
test_files: []
|
data/test/abstract_unit.rb
DELETED
@@ -1,165 +0,0 @@
|
|
1
|
-
require 'action_dispatch'
|
2
|
-
require 'action_controller'
|
3
|
-
require 'active_support/dependencies'
|
4
|
-
|
5
|
-
def active_support_4_0?
|
6
|
-
ActiveSupport::VERSION::MAJOR == 4 && ActiveSupport::VERSION::MINOR == 0
|
7
|
-
end
|
8
|
-
|
9
|
-
if active_support_4_0?
|
10
|
-
require 'active_support/core_ext/class/attribute_accessors'
|
11
|
-
else
|
12
|
-
require 'active_support/core_ext/module/attribute_accessors'
|
13
|
-
end
|
14
|
-
|
15
|
-
module SetupOnce
|
16
|
-
extend ActiveSupport::Concern
|
17
|
-
|
18
|
-
included do
|
19
|
-
cattr_accessor :setup_once_block
|
20
|
-
self.setup_once_block = nil
|
21
|
-
|
22
|
-
setup :run_setup_once
|
23
|
-
end
|
24
|
-
|
25
|
-
module ClassMethods
|
26
|
-
def setup_once(&block)
|
27
|
-
self.setup_once_block = block
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
def run_setup_once
|
33
|
-
if self.setup_once_block
|
34
|
-
self.setup_once_block.call
|
35
|
-
self.setup_once_block = nil
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
|
41
|
-
|
42
|
-
module ActiveSupport
|
43
|
-
class TestCase
|
44
|
-
include SetupOnce
|
45
|
-
# Hold off drawing routes until all the possible controller classes
|
46
|
-
# have been loaded.
|
47
|
-
setup_once do
|
48
|
-
SharedTestRoutes.draw do
|
49
|
-
get ':controller(/:action)'
|
50
|
-
end
|
51
|
-
|
52
|
-
ActionDispatch::IntegrationTest.app.routes.draw do
|
53
|
-
get ':controller(/:action)'
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
class RoutedRackApp
|
60
|
-
attr_reader :routes
|
61
|
-
|
62
|
-
def initialize(routes, &blk)
|
63
|
-
@routes = routes
|
64
|
-
@stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
|
65
|
-
end
|
66
|
-
|
67
|
-
def call(env)
|
68
|
-
@stack.call(env)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
|
73
|
-
setup do
|
74
|
-
@routes = SharedTestRoutes
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.build_app(routes = nil)
|
78
|
-
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
|
79
|
-
middleware.use "ActionDispatch::DebugExceptions"
|
80
|
-
middleware.use "ActionDispatch::Callbacks"
|
81
|
-
middleware.use "ActionDispatch::ParamsParser"
|
82
|
-
middleware.use "ActionDispatch::Cookies"
|
83
|
-
middleware.use "ActionDispatch::Flash"
|
84
|
-
middleware.use "Rack::Head"
|
85
|
-
yield(middleware) if block_given?
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
self.app = build_app
|
90
|
-
|
91
|
-
# Stub Rails dispatcher so it does not get controller references and
|
92
|
-
# simply return the controller#action as Rack::Body.
|
93
|
-
class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher
|
94
|
-
protected
|
95
|
-
def controller_reference(controller_param)
|
96
|
-
controller_param
|
97
|
-
end
|
98
|
-
|
99
|
-
def dispatch(controller, action, env)
|
100
|
-
[200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def self.stub_controllers
|
105
|
-
old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher
|
106
|
-
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
|
107
|
-
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher }
|
108
|
-
yield ActionDispatch::Routing::RouteSet.new
|
109
|
-
ensure
|
110
|
-
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
|
111
|
-
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher }
|
112
|
-
end
|
113
|
-
|
114
|
-
def with_routing(&block)
|
115
|
-
temporary_routes = ActionDispatch::Routing::RouteSet.new
|
116
|
-
old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
|
117
|
-
old_routes = SharedTestRoutes
|
118
|
-
silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }
|
119
|
-
|
120
|
-
yield temporary_routes
|
121
|
-
ensure
|
122
|
-
self.class.app = old_app
|
123
|
-
silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
|
124
|
-
end
|
125
|
-
|
126
|
-
def with_autoload_path(path)
|
127
|
-
path = File.join(File.dirname(__FILE__), "fixtures", path)
|
128
|
-
if ActiveSupport::Dependencies.autoload_paths.include?(path)
|
129
|
-
yield
|
130
|
-
else
|
131
|
-
begin
|
132
|
-
ActiveSupport::Dependencies.autoload_paths << path
|
133
|
-
yield
|
134
|
-
ensure
|
135
|
-
ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
|
136
|
-
ActiveSupport::Dependencies.clear
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
module ActionController
|
143
|
-
class Base
|
144
|
-
include ActionController::Testing
|
145
|
-
# This stub emulates the Railtie including the URL helpers from a Rails application
|
146
|
-
include SharedTestRoutes.url_helpers
|
147
|
-
include SharedTestRoutes.mounted_helpers
|
148
|
-
|
149
|
-
#self.view_paths = FIXTURE_LOAD_PATH
|
150
|
-
|
151
|
-
def self.test_routes(&block)
|
152
|
-
routes = ActionDispatch::Routing::RouteSet.new
|
153
|
-
routes.draw(&block)
|
154
|
-
include routes.url_helpers
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
class TestCase
|
159
|
-
include ActionDispatch::TestProcess
|
160
|
-
|
161
|
-
setup do
|
162
|
-
@routes = SharedTestRoutes
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'abstract_unit'
|
3
|
-
require 'action_controller/accessible_params_wrapper'
|
4
|
-
|
5
|
-
module ParamsWrapperTestHelp
|
6
|
-
def with_default_wrapper_options(&block)
|
7
|
-
@controller.class._set_wrapper_options({:format => [:json]})
|
8
|
-
@controller.class.inherited(@controller.class)
|
9
|
-
yield
|
10
|
-
end
|
11
|
-
|
12
|
-
def assert_parameters(expected)
|
13
|
-
assert_equal expected, self.class.controller_class.last_parameters
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class AccessibleParamsWrapperTest < ActionController::TestCase
|
18
|
-
include ParamsWrapperTestHelp
|
19
|
-
|
20
|
-
class UsersController < ActionController::Base
|
21
|
-
class << self
|
22
|
-
attr_accessor :last_parameters
|
23
|
-
end
|
24
|
-
|
25
|
-
def parse
|
26
|
-
self.class.last_parameters = request.params.except(:controller, :action)
|
27
|
-
head :ok
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class User; end
|
32
|
-
class Person; end
|
33
|
-
|
34
|
-
tests UsersController
|
35
|
-
|
36
|
-
def teardown
|
37
|
-
UsersController.last_parameters = nil
|
38
|
-
end
|
39
|
-
|
40
|
-
def test_derived_wrapped_keys_from_matching_model
|
41
|
-
User.expects(:respond_to?).with(:accessible_attributes).returns(false)
|
42
|
-
User.expects(:respond_to?).with(:attribute_names).returns(true)
|
43
|
-
User.expects(:attribute_names).twice.returns(["username"])
|
44
|
-
|
45
|
-
with_default_wrapper_options do
|
46
|
-
@request.env['CONTENT_TYPE'] = 'application/json'
|
47
|
-
post :parse, { 'username' => 'sikachu', 'title' => 'Developer' }
|
48
|
-
assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }})
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_derived_wrapped_keys_from_specified_model
|
53
|
-
with_default_wrapper_options do
|
54
|
-
Person.expects(:respond_to?).with(:accessible_attributes).returns(false)
|
55
|
-
Person.expects(:respond_to?).with(:attribute_names).returns(true)
|
56
|
-
Person.expects(:attribute_names).twice.returns(["username"])
|
57
|
-
|
58
|
-
UsersController.wrap_parameters Person
|
59
|
-
|
60
|
-
@request.env['CONTENT_TYPE'] = 'application/json'
|
61
|
-
post :parse, { 'username' => 'sikachu', 'title' => 'Developer' }
|
62
|
-
assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }})
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def test_accessible_wrapped_keys_from_matching_model
|
67
|
-
User.expects(:respond_to?).with(:accessible_attributes).returns(true)
|
68
|
-
User.expects(:accessible_attributes).with(:default).twice.returns(["username"])
|
69
|
-
|
70
|
-
with_default_wrapper_options do
|
71
|
-
@request.env['CONTENT_TYPE'] = 'application/json'
|
72
|
-
post :parse, { 'username' => 'sikachu', 'title' => 'Developer' }
|
73
|
-
assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }})
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
data/test/ar_helper.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
|
3
|
-
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
4
|
-
|
5
|
-
ActiveRecord::Schema.verbose = false
|
6
|
-
ActiveRecord::Schema.define do
|
7
|
-
create_table :accounts, :force => true do |t|
|
8
|
-
t.integer :firm_id
|
9
|
-
t.string :firm_name
|
10
|
-
t.integer :credit_limit
|
11
|
-
end
|
12
|
-
|
13
|
-
create_table :companies, :force => true do |t|
|
14
|
-
t.string :type
|
15
|
-
t.integer :firm_id
|
16
|
-
t.string :firm_name
|
17
|
-
t.string :name
|
18
|
-
t.integer :client_of
|
19
|
-
t.integer :rating, :default => 1
|
20
|
-
t.integer :account_id
|
21
|
-
t.string :description, :default => ""
|
22
|
-
end
|
23
|
-
|
24
|
-
add_index :companies, [:firm_id, :type, :rating], :name => "company_index"
|
25
|
-
add_index :companies, [:firm_id, :type], :name => "company_partial_index", :where => "rating > 10"
|
26
|
-
|
27
|
-
create_table :keyboards, :force => true, :id => false do |t|
|
28
|
-
t.primary_key :key_number
|
29
|
-
t.string :name
|
30
|
-
end
|
31
|
-
|
32
|
-
create_table :people, :force => true do |t|
|
33
|
-
t.string :first_name, :null => false
|
34
|
-
t.string :gender, :limit => 1
|
35
|
-
t.string :comments
|
36
|
-
t.references :best_friend
|
37
|
-
t.references :best_friend_of
|
38
|
-
t.timestamps
|
39
|
-
end
|
40
|
-
|
41
|
-
create_table :subscribers, :force => true, :id => false do |t|
|
42
|
-
t.string :nick, :null => false
|
43
|
-
t.string :name
|
44
|
-
end
|
45
|
-
add_index :subscribers, :nick, :unique => true
|
46
|
-
|
47
|
-
create_table :tasks, :force => true do |t|
|
48
|
-
t.datetime :starting
|
49
|
-
t.datetime :ending
|
50
|
-
end
|
51
|
-
|
52
|
-
create_table :pirates, :force => true do |t|
|
53
|
-
t.string :name
|
54
|
-
end
|
55
|
-
|
56
|
-
create_table :groups, :force => true do |t|
|
57
|
-
end
|
58
|
-
|
59
|
-
create_table :memberships, :force => true do |t|
|
60
|
-
t.integer "group_id"
|
61
|
-
t.integer "pirate_id"
|
62
|
-
end
|
63
|
-
|
64
|
-
create_table :teams, :force => true
|
65
|
-
create_table :wolves, :force => true
|
66
|
-
create_table :vampires, :force => true
|
67
|
-
create_table :battles, :force => true do |t|
|
68
|
-
t.integer "team_id"
|
69
|
-
t.integer "battle_id"
|
70
|
-
t.string "battle_type"
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type')
|