wallaby-active_record 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/lib/adapters/wallaby/active_record/cancancan_provider.rb +9 -0
- data/lib/adapters/wallaby/active_record/default_provider.rb +9 -0
- data/lib/adapters/wallaby/active_record/model_decorator/fields_builder/association_builder.rb +52 -0
- data/lib/adapters/wallaby/active_record/model_decorator/fields_builder/polymorphic_builder.rb +52 -0
- data/lib/adapters/wallaby/active_record/model_decorator/fields_builder/sti_builder.rb +50 -0
- data/lib/adapters/wallaby/active_record/model_decorator/fields_builder.rb +66 -0
- data/lib/adapters/wallaby/active_record/model_decorator/title_field_finder.rb +32 -0
- data/lib/adapters/wallaby/active_record/model_decorator.rb +155 -0
- data/lib/adapters/wallaby/active_record/model_finder.rb +45 -0
- data/lib/adapters/wallaby/active_record/model_pagination_provider.rb +34 -0
- data/lib/adapters/wallaby/active_record/model_service_provider/normalizer.rb +54 -0
- data/lib/adapters/wallaby/active_record/model_service_provider/permitter.rb +68 -0
- data/lib/adapters/wallaby/active_record/model_service_provider/querier/transformer.rb +78 -0
- data/lib/adapters/wallaby/active_record/model_service_provider/querier.rb +172 -0
- data/lib/adapters/wallaby/active_record/model_service_provider/validator.rb +37 -0
- data/lib/adapters/wallaby/active_record/model_service_provider.rb +166 -0
- data/lib/adapters/wallaby/active_record/pundit_provider.rb +19 -0
- data/lib/adapters/wallaby/active_record.rb +7 -0
- data/lib/wallaby/active_record/version.rb +7 -0
- data/lib/wallaby/active_record.rb +38 -0
- metadata +152 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
class ActiveRecord
|
5
|
+
class ModelServiceProvider
|
6
|
+
# Filter the params
|
7
|
+
class Permitter
|
8
|
+
# @param model_decorator [Wallaby::ModelDecorator]
|
9
|
+
def initialize(model_decorator)
|
10
|
+
@model_decorator = model_decorator
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Array<String>] a list of field names of general types
|
14
|
+
def simple_field_names
|
15
|
+
field_names =
|
16
|
+
non_range_fields.keys +
|
17
|
+
belongs_to_fields.map do |_, metadata|
|
18
|
+
[metadata[:foreign_key], metadata[:polymorphic_type]]
|
19
|
+
end.flatten.compact
|
20
|
+
fields = [@model_decorator.primary_key, 'created_at', 'updated_at']
|
21
|
+
field_names.reject { |field_name| fields.include? field_name }
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Array<String>] a list of field names of range and association
|
25
|
+
def compound_hashed_fields
|
26
|
+
field_names =
|
27
|
+
range_fields.keys +
|
28
|
+
many_association_fields.map { |_, metadata| metadata[:foreign_key] }
|
29
|
+
field_names.each_with_object({}) { |name, hash| hash[name] = [] }
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
# @return [Array<String>] a list of field names that ain't association
|
35
|
+
def non_association_fields
|
36
|
+
@model_decorator.fields.reject { |_, metadata| metadata[:is_association] }
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Array<String>] a list of field names that ain't range
|
40
|
+
def non_range_fields
|
41
|
+
non_association_fields.reject { |_, metadata| /range|point/ =~ metadata[:type] }
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Array<String>] a list of range field names
|
45
|
+
def range_fields
|
46
|
+
non_association_fields.select { |_, metadata| /range|point/ =~ metadata[:type] }
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Array<String>] a list of association field names
|
50
|
+
def association_fields
|
51
|
+
@model_decorator.fields.select { |_, metadata| metadata[:is_association] && !metadata[:has_scope] }
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Array<String>] a list of many association field names:
|
55
|
+
# - has_many
|
56
|
+
# - has_and_belongs_to_many
|
57
|
+
def many_association_fields
|
58
|
+
association_fields.select { |_, metadata| /many/ =~ metadata[:type] }
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [Array<String>] a list of belongs_to association field names
|
62
|
+
def belongs_to_fields
|
63
|
+
association_fields.select { |_, metadata| metadata[:type] == 'belongs_to' }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
class ActiveRecord
|
5
|
+
class ModelServiceProvider
|
6
|
+
class Querier
|
7
|
+
# Build up query using the results
|
8
|
+
class Transformer < Parslet::Transform
|
9
|
+
SIMPLE_OPERATORS = {
|
10
|
+
':' => :eq,
|
11
|
+
':=' => :eq,
|
12
|
+
':!' => :not_eq,
|
13
|
+
':!=' => :not_eq,
|
14
|
+
':<>' => :not_eq,
|
15
|
+
':~' => :matches,
|
16
|
+
':^' => :matches,
|
17
|
+
':$' => :matches,
|
18
|
+
':!~' => :does_not_match,
|
19
|
+
':!^' => :does_not_match,
|
20
|
+
':!$' => :does_not_match,
|
21
|
+
':>' => :gt,
|
22
|
+
':>=' => :gteq,
|
23
|
+
':<' => :lt,
|
24
|
+
':<=' => :lteq
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
SEQUENCE_OPERATORS = {
|
28
|
+
':' => :in,
|
29
|
+
':=' => :in,
|
30
|
+
':!' => :not_in,
|
31
|
+
':!=' => :not_in,
|
32
|
+
':<>' => :not_in,
|
33
|
+
':()' => :between,
|
34
|
+
':!()' => :not_between
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
# For single keyword
|
38
|
+
rule keyword: simple(:value) do
|
39
|
+
value.try :to_str
|
40
|
+
end
|
41
|
+
|
42
|
+
# For multiple keywords
|
43
|
+
rule keyword: sequence(:value) do
|
44
|
+
value.presence.try :map, :to_str
|
45
|
+
end
|
46
|
+
|
47
|
+
# For operators
|
48
|
+
rule left: simple(:left), op: simple(:op), right: simple(:right) do
|
49
|
+
oped = op.try :to_str
|
50
|
+
operator = SIMPLE_OPERATORS[oped]
|
51
|
+
# skip if the operator is unknown
|
52
|
+
next unless operator
|
53
|
+
|
54
|
+
lefted = left.try :to_str
|
55
|
+
convert =
|
56
|
+
case oped
|
57
|
+
when ':~', ':!~' then "%#{right}%"
|
58
|
+
when ':^', ':!^' then "#{right}%"
|
59
|
+
when ':$', ':!$' then "%#{right}"
|
60
|
+
end
|
61
|
+
{ left: lefted, op: operator, right: convert || right }
|
62
|
+
end
|
63
|
+
|
64
|
+
# For operators that have multiple items
|
65
|
+
rule left: simple(:left), op: simple(:op), right: sequence(:right) do
|
66
|
+
oped = op.try :to_str
|
67
|
+
operator = SEQUENCE_OPERATORS[oped]
|
68
|
+
next unless operator
|
69
|
+
|
70
|
+
lefted = left.try :to_str
|
71
|
+
convert = Range.new right.try(:first), right.try(:last) if %w(:() :!()).include?(oped)
|
72
|
+
{ left: lefted, op: operator, right: convert || right }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
class ActiveRecord
|
5
|
+
class ModelServiceProvider
|
6
|
+
# Query builder
|
7
|
+
class Querier
|
8
|
+
TEXT_FIELDS = %w(string text citext longtext tinytext mediumtext).freeze
|
9
|
+
|
10
|
+
# @param model_decorator [Wallaby::ModelDecorator]
|
11
|
+
def initialize(model_decorator)
|
12
|
+
@model_decorator = model_decorator
|
13
|
+
@model_class = @model_decorator.model_class
|
14
|
+
end
|
15
|
+
|
16
|
+
# Pull out the query expression string from the parameter `q`,
|
17
|
+
# use parser to understand the expression, then use transformer to run
|
18
|
+
# SQL arel query.
|
19
|
+
# @param params [ActionController::Parameters]
|
20
|
+
# @return [ActiveRecord::Relation]
|
21
|
+
def search(params)
|
22
|
+
filter_name, keywords, field_queries = extract params
|
23
|
+
scope = filtered_by filter_name
|
24
|
+
query = text_search keywords
|
25
|
+
query = field_search field_queries, query
|
26
|
+
scope.where query
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# @see Wallaby::Parser
|
32
|
+
def parser
|
33
|
+
@parser ||= Parser.new
|
34
|
+
end
|
35
|
+
|
36
|
+
# @see Wallaby::ActiveRecord::ModelServiceProvider::Querier::Transformer
|
37
|
+
def transformer
|
38
|
+
@transformer ||= Transformer.new
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Arel::Table] arel table
|
42
|
+
def table
|
43
|
+
@model_class.arel_table
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param params [ActionController::Parameters]
|
47
|
+
# @return [Array<String, Array, Array>] a list of object for other
|
48
|
+
# method to use.
|
49
|
+
def extract(params)
|
50
|
+
expressions = to_expressions params
|
51
|
+
keywords = expressions.select { |v| v.is_a? String }
|
52
|
+
field_queries = expressions.select { |v| v.is_a? Hash }
|
53
|
+
filter_name = params[:filter]
|
54
|
+
[filter_name, keywords, field_queries]
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param params [ActionController::Parameters]
|
58
|
+
# @return [Array] a list of transformed operations
|
59
|
+
def to_expressions(params)
|
60
|
+
parsed = parser.parse(params[:q] || EMPTY_STRING)
|
61
|
+
converted = transformer.apply parsed
|
62
|
+
converted.is_a?(Array) ? converted : [converted]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Use the filter name to find out the scope in the following precedents:
|
66
|
+
# - scope from metadata
|
67
|
+
# - defined scope from the model
|
68
|
+
# - unscoped
|
69
|
+
# @param filter_name [String] filter name
|
70
|
+
# @return [ActiveRecord::Relation]
|
71
|
+
def filtered_by(filter_name)
|
72
|
+
valid_filter_name =
|
73
|
+
FilterUtils.filter_name_by(filter_name, @model_decorator.filters)
|
74
|
+
scope = find_scope(valid_filter_name)
|
75
|
+
if scope.blank? then unscoped
|
76
|
+
elsif scope.is_a?(Proc) then @model_class.instance_exec(&scope)
|
77
|
+
elsif @model_class.respond_to?(scope)
|
78
|
+
@model_class.public_send(scope)
|
79
|
+
else unscoped
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Find out the scope for given filter
|
84
|
+
# - from metadata
|
85
|
+
# - filter name itself
|
86
|
+
# @param filter_name [String] filter name
|
87
|
+
# @return [String]
|
88
|
+
def find_scope(filter_name)
|
89
|
+
filter = @model_decorator.filters[filter_name] || {}
|
90
|
+
filter[:scope] || filter_name
|
91
|
+
end
|
92
|
+
|
93
|
+
# Unscoped query
|
94
|
+
# @return [ActiveRecord::Relation]
|
95
|
+
def unscoped
|
96
|
+
@model_class.where nil
|
97
|
+
end
|
98
|
+
|
99
|
+
# Search text for the text columns that appear in `index_field_names`
|
100
|
+
# @param keywords [String] keywords
|
101
|
+
# @param query [ActiveRecord::Relation, nil]
|
102
|
+
# @return [ActiveRecord::Relation]
|
103
|
+
def text_search(keywords, query = nil)
|
104
|
+
return query unless keywords_check? keywords
|
105
|
+
|
106
|
+
text_fields.each do |field_name|
|
107
|
+
sub_query = nil
|
108
|
+
keywords.each do |keyword|
|
109
|
+
exp = table[field_name].matches("%#{keyword}%")
|
110
|
+
sub_query = sub_query.try(:and, exp) || exp
|
111
|
+
end
|
112
|
+
query = query.try(:or, sub_query) || sub_query
|
113
|
+
end
|
114
|
+
query
|
115
|
+
end
|
116
|
+
|
117
|
+
# Perform SQL query for the colon query (e.g. data:<2000-01-01)
|
118
|
+
# @param field_queries [Array]
|
119
|
+
# @param query [ActiveRecord::Relation]
|
120
|
+
# @return [ActiveRecord::Relation]
|
121
|
+
def field_search(field_queries, query)
|
122
|
+
return query unless field_check? field_queries
|
123
|
+
|
124
|
+
field_queries.each do |exp|
|
125
|
+
sub_query = table[exp[:left]].try(exp[:op], exp[:right])
|
126
|
+
query = query.try(:and, sub_query) || sub_query
|
127
|
+
end
|
128
|
+
query
|
129
|
+
end
|
130
|
+
|
131
|
+
# @return [Array<String>] a list of text fields from `index_field_names`
|
132
|
+
def text_fields
|
133
|
+
@text_fields ||= begin
|
134
|
+
index_field_names = @model_decorator.index_field_names.map(&:to_s)
|
135
|
+
@model_decorator.fields.select do |field_name, metadata|
|
136
|
+
index_field_names.include?(field_name) &&
|
137
|
+
TEXT_FIELDS.include?(metadata[:type].to_s)
|
138
|
+
end.keys
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# @param keywords [Array<String>] a list of keywords
|
143
|
+
# @return [Boolean] false when keywords are empty
|
144
|
+
# true when text fields for query exist
|
145
|
+
# otherwise, raise exception
|
146
|
+
def keywords_check?(keywords)
|
147
|
+
return false if keywords.blank?
|
148
|
+
return true if text_fields.present?
|
149
|
+
|
150
|
+
message = I18n.t 'errors.unprocessable_entity.keyword_search'
|
151
|
+
raise UnprocessableEntity, message
|
152
|
+
end
|
153
|
+
|
154
|
+
# @param field_queries [Array]
|
155
|
+
# @return [Boolean] false when field queries are blank
|
156
|
+
# true when the fields used are valid (exist in `fields`)
|
157
|
+
# otherwise, raise exception
|
158
|
+
def field_check?(field_queries)
|
159
|
+
return false if field_queries.blank?
|
160
|
+
|
161
|
+
fields = field_queries.map { |exp| exp[:left] }
|
162
|
+
invalid_fields = fields - @model_decorator.fields.keys
|
163
|
+
return true if invalid_fields.blank?
|
164
|
+
|
165
|
+
message = I18n.t 'errors.unprocessable_entity.field_colon_search',
|
166
|
+
invalid_fields: invalid_fields.to_sentence
|
167
|
+
raise UnprocessableEntity, message
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
class ActiveRecord
|
5
|
+
class ModelServiceProvider
|
6
|
+
# Validator
|
7
|
+
class Validator
|
8
|
+
# @param model_decorator [Wallaby::ModelDecorator]
|
9
|
+
def initialize(model_decorator)
|
10
|
+
@model_decorator = model_decorator
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param resource [Object] resource object
|
14
|
+
# @return [Boolean] whether the resource object is valid
|
15
|
+
def valid?(resource)
|
16
|
+
resource.attributes.each do |field_name, values|
|
17
|
+
metadata = @model_decorator.fields[field_name]
|
18
|
+
next if valid_range_type? values, metadata
|
19
|
+
|
20
|
+
resource.errors.add field_name, 'required for range data'
|
21
|
+
end
|
22
|
+
resource.errors.blank?
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# @param values [Array]
|
28
|
+
# @return [Boolean] whether the values are valid range values
|
29
|
+
def valid_range_type?(values, metadata)
|
30
|
+
!metadata \
|
31
|
+
|| !%w(daterange tsrange tstzrange).include?(metadata[:type]) \
|
32
|
+
|| !values.try(:any?, &:blank?)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
class ActiveRecord
|
5
|
+
# Model service provider
|
6
|
+
# @see Wallaby::ModelServiceProvider
|
7
|
+
class ModelServiceProvider < ::Wallaby::ModelServiceProvider
|
8
|
+
# @param params [ActionController::Parameters]
|
9
|
+
# @param action [String, Symbol]
|
10
|
+
# @param authorizer
|
11
|
+
# @return [ActionController::Parameters] whitelisted parameters
|
12
|
+
# @see Wallaby::ModelServiceProvider#permit
|
13
|
+
def permit(params, action, authorizer)
|
14
|
+
authorized_fields = authorizer.permit_params action, @model_class
|
15
|
+
params.require(param_key).permit(authorized_fields || permitted_fields)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @note Pagination free here. Since somewhere might need the collection without any pagination
|
19
|
+
# @param params [ActionController::Parameters]
|
20
|
+
# @param authorizer [Ability] for now
|
21
|
+
# @return [ActiveRecord::Relation] relation
|
22
|
+
# @see Wallaby::ModelServiceProvider#collection
|
23
|
+
def collection(params, authorizer)
|
24
|
+
query = querier.search params
|
25
|
+
query = query.order params[:sort] if params[:sort].present?
|
26
|
+
authorizer.accessible_for :index, query
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param query [ActiveRecord::Relation]
|
30
|
+
# @param params [ActionController::Parameters]
|
31
|
+
# @return [ActiveRecord::Relation] paginated query
|
32
|
+
# @see Wallaby::ModelServiceProvider#paginate
|
33
|
+
def paginate(query, params)
|
34
|
+
per = params[:per] || Wallaby.configuration.pagination.page_size
|
35
|
+
query = query.page params[:page] if query.respond_to? :page
|
36
|
+
query = query.per per if query.respond_to? :per
|
37
|
+
query
|
38
|
+
end
|
39
|
+
|
40
|
+
# @note No mass assignment happens here!
|
41
|
+
# @return [Object] new resource object
|
42
|
+
# @see Wallaby::ModelServiceProvider#new
|
43
|
+
def new(_params, _authorizer)
|
44
|
+
@model_class.new
|
45
|
+
end
|
46
|
+
|
47
|
+
# @note No mass assignment happens here!
|
48
|
+
# Find the record using id.
|
49
|
+
# @param id [Integer, String]
|
50
|
+
# @return [Object] persisted resource object
|
51
|
+
# @raise [Wallaby::ResourceNotFound] when record is not found
|
52
|
+
# @see Wallaby::ModelServiceProvider#find
|
53
|
+
def find(id, _params, _authorizer)
|
54
|
+
@model_class.find id
|
55
|
+
rescue ::ActiveRecord::RecordNotFound
|
56
|
+
raise ResourceNotFound, id
|
57
|
+
end
|
58
|
+
|
59
|
+
# Assign resource with new values and store it in database as new record.
|
60
|
+
# @param resource [Object]
|
61
|
+
# @param params [ActionController::Parameters]
|
62
|
+
# @param authorizer [Wallaby::ModelAuthorizer]
|
63
|
+
# @see Wallaby::ModelServiceProvider#create
|
64
|
+
def create(resource, params, authorizer)
|
65
|
+
save __callee__, resource, params, authorizer
|
66
|
+
end
|
67
|
+
|
68
|
+
# Assign resource with new values and store it in database as an update.
|
69
|
+
# @param resource [Object]
|
70
|
+
# @param params [ActionController::Parameters]
|
71
|
+
# @param authorizer [Wallaby::ModelAuthorizer]
|
72
|
+
# @see Wallaby::ModelServiceProvider#update
|
73
|
+
def update(resource, params, authorizer)
|
74
|
+
save __callee__, resource, params, authorizer
|
75
|
+
end
|
76
|
+
|
77
|
+
# Remove a record from database
|
78
|
+
# @param resource [Object]
|
79
|
+
# @see Wallaby::ModelServiceProvider#destroy
|
80
|
+
def destroy(resource, _params, _authorizer)
|
81
|
+
resource.destroy
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
# Save the record
|
87
|
+
# @param action [String] `create`, `update`
|
88
|
+
# @param resource [Object]
|
89
|
+
# @param params [ActionController::Parameters]
|
90
|
+
# @param authorizer [Wallaby::ModelAuthorizer]
|
91
|
+
# @return resource itself
|
92
|
+
# @raise [ActiveRecord::StatementInvalid, ActiveModel::UnknownAttributeError, ActiveRecord::UnknownAttributeError]
|
93
|
+
def save(action, resource, params, authorizer)
|
94
|
+
resource.assign_attributes normalize params
|
95
|
+
ensure_attributes_for authorizer, action, resource
|
96
|
+
resource.save if valid? resource
|
97
|
+
resource
|
98
|
+
rescue ::ActiveRecord::ActiveRecordError, ActiveModel::ForbiddenAttributesError, unknown_attribute_error => e
|
99
|
+
resource.errors.add :base, e.message
|
100
|
+
resource
|
101
|
+
end
|
102
|
+
|
103
|
+
# Normalize params
|
104
|
+
# @param params [ActionController::Parameters]
|
105
|
+
def normalize(params)
|
106
|
+
normalizer.normalize params
|
107
|
+
end
|
108
|
+
|
109
|
+
# See if a resource is valid
|
110
|
+
# @param resource [Object]
|
111
|
+
# @return [Boolean]
|
112
|
+
def valid?(resource)
|
113
|
+
validator.valid? resource
|
114
|
+
end
|
115
|
+
|
116
|
+
# To make sure that the record can be updated with the values that are
|
117
|
+
# allowed to.
|
118
|
+
# @param authorizer [Object]
|
119
|
+
# @param action [String]
|
120
|
+
# @param resource [Object]
|
121
|
+
def ensure_attributes_for(authorizer, action, resource)
|
122
|
+
return if authorizer.blank?
|
123
|
+
|
124
|
+
restricted_conditions = authorizer.attributes_for action, resource
|
125
|
+
resource.assign_attributes restricted_conditions
|
126
|
+
end
|
127
|
+
|
128
|
+
# @return [String] param key
|
129
|
+
def param_key
|
130
|
+
@model_class.model_name.param_key
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return [Array] the list of attributes to whitelist for mass assignment
|
134
|
+
def permitted_fields
|
135
|
+
@permitted_fields ||=
|
136
|
+
permitter.simple_field_names << permitter.compound_hashed_fields
|
137
|
+
end
|
138
|
+
|
139
|
+
# @see Wallaby::ModelServiceProvider::Permitter
|
140
|
+
def permitter
|
141
|
+
@permitter ||= Permitter.new @model_decorator
|
142
|
+
end
|
143
|
+
|
144
|
+
# @see Wallaby::ModelServiceProvider::Querier
|
145
|
+
def querier
|
146
|
+
@querier ||= Querier.new @model_decorator
|
147
|
+
end
|
148
|
+
|
149
|
+
# @see Wallaby::ModelServiceProvider::Normalizer
|
150
|
+
def normalizer
|
151
|
+
@normalizer ||= Normalizer.new @model_decorator
|
152
|
+
end
|
153
|
+
|
154
|
+
# @see Wallaby::ModelServiceProvider::Validator
|
155
|
+
def validator
|
156
|
+
@validator ||= Validator.new @model_decorator
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [Class] ActiveModel::UnknownAttributeError if Rails 4
|
160
|
+
# @return [Class] ActiveRecord::UnknownAttributeError if Rails 5
|
161
|
+
def unknown_attribute_error
|
162
|
+
(defined?(::ActiveModel::UnknownAttributeError) ? ::ActiveModel : ::ActiveRecord)::UnknownAttributeError
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wallaby
|
4
|
+
class ActiveRecord
|
5
|
+
# Pundit provider for ActiveRecord
|
6
|
+
class PunditProvider < PunditAuthorizationProvider
|
7
|
+
# Filter a scope
|
8
|
+
# @param _action [Symbol, String]
|
9
|
+
# @param scope [Object]
|
10
|
+
# @return [Object]
|
11
|
+
def accessible_for(_action, scope)
|
12
|
+
Pundit.policy_scope! user, scope
|
13
|
+
rescue Pundit::NotDefinedError
|
14
|
+
Rails.logger.warn I18n.t('errors.pundit.not_found.scope_policy', scope: scope)
|
15
|
+
scope
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kaminari'
|
4
|
+
require 'wallaby/core'
|
5
|
+
|
6
|
+
require 'wallaby/active_record/version'
|
7
|
+
|
8
|
+
# All files required for ActiveRecord ORM
|
9
|
+
require 'adapters/wallaby/active_record'
|
10
|
+
require 'adapters/wallaby/active_record/model_finder'
|
11
|
+
|
12
|
+
# ModelPaginationProvider: begin
|
13
|
+
require 'adapters/wallaby/active_record/model_pagination_provider'
|
14
|
+
# ModelPaginationProvider: end
|
15
|
+
|
16
|
+
# ModelDecorator: begin
|
17
|
+
require 'adapters/wallaby/active_record/model_decorator'
|
18
|
+
require 'adapters/wallaby/active_record/model_decorator/title_field_finder'
|
19
|
+
require 'adapters/wallaby/active_record/model_decorator/fields_builder'
|
20
|
+
require 'adapters/wallaby/active_record/model_decorator/fields_builder/sti_builder'
|
21
|
+
require 'adapters/wallaby/active_record/model_decorator/fields_builder/association_builder'
|
22
|
+
require 'adapters/wallaby/active_record/model_decorator/fields_builder/polymorphic_builder'
|
23
|
+
# ModelDecorator: end
|
24
|
+
|
25
|
+
# ModelServiceProvider: begin
|
26
|
+
require 'adapters/wallaby/active_record/model_service_provider'
|
27
|
+
require 'adapters/wallaby/active_record/model_service_provider/normalizer'
|
28
|
+
require 'adapters/wallaby/active_record/model_service_provider/permitter'
|
29
|
+
require 'adapters/wallaby/active_record/model_service_provider/querier'
|
30
|
+
require 'adapters/wallaby/active_record/model_service_provider/querier/transformer'
|
31
|
+
require 'adapters/wallaby/active_record/model_service_provider/validator'
|
32
|
+
# ModelServiceProvider: end
|
33
|
+
|
34
|
+
# AuthorizationProvider: begin
|
35
|
+
require 'adapters/wallaby/active_record/default_provider'
|
36
|
+
require 'adapters/wallaby/active_record/cancancan_provider'
|
37
|
+
require 'adapters/wallaby/active_record/pundit_provider'
|
38
|
+
# AuthorizationProvider: end
|