api_maker 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +476 -0
- data/Rakefile +27 -0
- data/app/channels/api_maker/subscriptions_channel.rb +80 -0
- data/app/controllers/api_maker/base_controller.rb +32 -0
- data/app/controllers/api_maker/commands_controller.rb +26 -0
- data/app/controllers/api_maker/devise_controller.rb +60 -0
- data/app/controllers/api_maker/session_statuses_controller.rb +33 -0
- data/app/services/api_maker/application_service.rb +7 -0
- data/app/services/api_maker/collection_command_service.rb +24 -0
- data/app/services/api_maker/command_response.rb +67 -0
- data/app/services/api_maker/command_service.rb +31 -0
- data/app/services/api_maker/create_command.rb +62 -0
- data/app/services/api_maker/create_command_service.rb +18 -0
- data/app/services/api_maker/destroy_command.rb +39 -0
- data/app/services/api_maker/destroy_command_service.rb +22 -0
- data/app/services/api_maker/generate_react_native_api_service.rb +61 -0
- data/app/services/api_maker/index_command.rb +96 -0
- data/app/services/api_maker/index_command_service.rb +22 -0
- data/app/services/api_maker/js_method_namer_service.rb +11 -0
- data/app/services/api_maker/member_command_service.rb +25 -0
- data/app/services/api_maker/model_content_generator_service.rb +108 -0
- data/app/services/api_maker/models_finder_service.rb +22 -0
- data/app/services/api_maker/models_generator_service.rb +104 -0
- data/app/services/api_maker/update_command.rb +43 -0
- data/app/services/api_maker/update_command_service.rb +21 -0
- data/app/services/api_maker/valid_command.rb +35 -0
- data/app/services/api_maker/valid_command_service.rb +21 -0
- data/app/views/api_maker/_data.html.erb +15 -0
- data/config/rails_best_practices.yml +55 -0
- data/config/routes.rb +7 -0
- data/lib/api_maker.rb +36 -0
- data/lib/api_maker/ability.rb +39 -0
- data/lib/api_maker/ability_loader.rb +21 -0
- data/lib/api_maker/action_controller_base_extensions.rb +5 -0
- data/lib/api_maker/base_command.rb +81 -0
- data/lib/api_maker/base_resource.rb +78 -0
- data/lib/api_maker/collection_serializer.rb +69 -0
- data/lib/api_maker/command_spec_helper.rb +57 -0
- data/lib/api_maker/configuration.rb +34 -0
- data/lib/api_maker/engine.rb +5 -0
- data/lib/api_maker/individual_command.rb +37 -0
- data/lib/api_maker/javascript/api.js +92 -0
- data/lib/api_maker/javascript/base-model.js +543 -0
- data/lib/api_maker/javascript/bootstrap/attribute-row.jsx +16 -0
- data/lib/api_maker/javascript/bootstrap/attribute-rows.jsx +47 -0
- data/lib/api_maker/javascript/bootstrap/card.jsx +79 -0
- data/lib/api_maker/javascript/bootstrap/checkbox.jsx +127 -0
- data/lib/api_maker/javascript/bootstrap/checkboxes.jsx +105 -0
- data/lib/api_maker/javascript/bootstrap/live-table.jsx +168 -0
- data/lib/api_maker/javascript/bootstrap/money-input.jsx +136 -0
- data/lib/api_maker/javascript/bootstrap/radio-buttons.jsx +80 -0
- data/lib/api_maker/javascript/bootstrap/select.jsx +168 -0
- data/lib/api_maker/javascript/bootstrap/string-input.jsx +203 -0
- data/lib/api_maker/javascript/cable-connection-pool.js +169 -0
- data/lib/api_maker/javascript/cable-subscription-pool.js +111 -0
- data/lib/api_maker/javascript/cable-subscription.js +33 -0
- data/lib/api_maker/javascript/collection.js +186 -0
- data/lib/api_maker/javascript/commands-pool.js +123 -0
- data/lib/api_maker/javascript/custom-error.js +14 -0
- data/lib/api_maker/javascript/deserializer.js +35 -0
- data/lib/api_maker/javascript/devise.js.erb +113 -0
- data/lib/api_maker/javascript/error-logger.js +119 -0
- data/lib/api_maker/javascript/event-connection.jsx +24 -0
- data/lib/api_maker/javascript/event-created.jsx +26 -0
- data/lib/api_maker/javascript/event-destroyed.jsx +26 -0
- data/lib/api_maker/javascript/event-emitter-listener.jsx +32 -0
- data/lib/api_maker/javascript/event-listener.jsx +41 -0
- data/lib/api_maker/javascript/event-updated.jsx +26 -0
- data/lib/api_maker/javascript/form-data-to-object.js +70 -0
- data/lib/api_maker/javascript/included.js +39 -0
- data/lib/api_maker/javascript/key-value-store.js +47 -0
- data/lib/api_maker/javascript/logger.js +23 -0
- data/lib/api_maker/javascript/model-name.js +21 -0
- data/lib/api_maker/javascript/model-template.js.erb +110 -0
- data/lib/api_maker/javascript/models-response-reader.js +43 -0
- data/lib/api_maker/javascript/paginate.jsx +128 -0
- data/lib/api_maker/javascript/params.js +68 -0
- data/lib/api_maker/javascript/resource-route.jsx +75 -0
- data/lib/api_maker/javascript/resource-routes.jsx +36 -0
- data/lib/api_maker/javascript/result.js +25 -0
- data/lib/api_maker/javascript/session-status-updater.js +113 -0
- data/lib/api_maker/javascript/sort-link.jsx +88 -0
- data/lib/api_maker/javascript/updated-attribute.jsx +60 -0
- data/lib/api_maker/loader.rb +14 -0
- data/lib/api_maker/memory_storage.rb +65 -0
- data/lib/api_maker/model_extensions.rb +96 -0
- data/lib/api_maker/permitted_params_argument.rb +12 -0
- data/lib/api_maker/preloader.rb +91 -0
- data/lib/api_maker/preloader_belongs_to.rb +58 -0
- data/lib/api_maker/preloader_has_many.rb +69 -0
- data/lib/api_maker/preloader_has_one.rb +70 -0
- data/lib/api_maker/preloader_through.rb +101 -0
- data/lib/api_maker/railtie.rb +14 -0
- data/lib/api_maker/relationship_includer.rb +42 -0
- data/lib/api_maker/resource_routing.rb +8 -0
- data/lib/api_maker/result_parser.rb +50 -0
- data/lib/api_maker/serializer.rb +86 -0
- data/lib/api_maker/spec_helper.rb +100 -0
- data/lib/api_maker/version.rb +3 -0
- data/lib/tasks/api_maker_tasks.rake +5 -0
- metadata +581 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
class ApiMaker::PreloaderHasMany
|
2
|
+
def initialize(ability:, args:, data:, collection:, reflection:, records:, select:)
|
3
|
+
@ability = ability
|
4
|
+
@args = args
|
5
|
+
@data = data
|
6
|
+
@collection = collection
|
7
|
+
@reflection = reflection
|
8
|
+
@records = records
|
9
|
+
@select = select
|
10
|
+
|
11
|
+
raise "No inverse of for #{@reflection.active_record.name}##{@reflection.name}" unless @reflection.inverse_of
|
12
|
+
end
|
13
|
+
|
14
|
+
def preload
|
15
|
+
models.each do |model|
|
16
|
+
preload_model(model)
|
17
|
+
end
|
18
|
+
|
19
|
+
{collection: models}
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def models
|
25
|
+
@models ||= begin
|
26
|
+
if @reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
27
|
+
query = ApiMaker::PreloaderThrough.new(collection: @collection, reflection: @reflection).models_query_through_reflection
|
28
|
+
else
|
29
|
+
primary_key_column = @reflection.options[:primary_key]&.to_sym || @collection.primary_key.to_sym
|
30
|
+
query = @reflection.klass.where(@reflection.foreign_key => @collection.map(&primary_key_column))
|
31
|
+
query = query.joins(@reflection.inverse_of.name)
|
32
|
+
end
|
33
|
+
|
34
|
+
query = query
|
35
|
+
.select(@reflection.klass.arel_table[Arel.star])
|
36
|
+
.select(@reflection.active_record.arel_table[@reflection.active_record.primary_key].as("api_maker_origin_id"))
|
37
|
+
|
38
|
+
query = query.accessible_by(@ability) if @ability
|
39
|
+
query.load
|
40
|
+
query
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def collection_name
|
45
|
+
@collection_name ||= ApiMaker::MemoryStorage.current.resource_for_model(@reflection.active_record).collection_name
|
46
|
+
end
|
47
|
+
|
48
|
+
def preload_model(model)
|
49
|
+
origin_data = find_origin_data_for_model(model)
|
50
|
+
|
51
|
+
origin_data.fetch(:r)[@reflection.name] ||= []
|
52
|
+
origin_data.fetch(:r).fetch(@reflection.name) << model.id
|
53
|
+
|
54
|
+
serializer = ApiMaker::Serializer.new(ability: @ability, args: @args, model: model, select: @select&.dig(model.class))
|
55
|
+
collection_name = serializer.resource.collection_name
|
56
|
+
|
57
|
+
@data.fetch(:included)[collection_name] ||= {}
|
58
|
+
@data.fetch(:included).fetch(collection_name)[model.id] ||= serializer
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_origin_data_for_model(model)
|
62
|
+
origin_id = model.read_attribute("api_maker_origin_id")
|
63
|
+
origin_data = @records.fetch(collection_name).fetch(origin_id)
|
64
|
+
|
65
|
+
raise "Couldn't find any origin data by that type (#{collection_name}) and ID (#{origin_id})" unless origin_data
|
66
|
+
|
67
|
+
origin_data
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class ApiMaker::PreloaderHasOne
|
2
|
+
def initialize(ability:, args:, data:, collection:, reflection:, records:, select: @select)
|
3
|
+
@ability = ability
|
4
|
+
@args = args
|
5
|
+
@data = data
|
6
|
+
@collection = collection
|
7
|
+
@reflection = reflection
|
8
|
+
@records = records
|
9
|
+
@select = select
|
10
|
+
|
11
|
+
raise "Records was nil" unless records
|
12
|
+
end
|
13
|
+
|
14
|
+
def collection_name
|
15
|
+
@collection_name ||= ApiMaker::MemoryStorage.current.resource_for_model(@reflection.active_record).collection_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def preload
|
19
|
+
models.each do |model|
|
20
|
+
ApiMaker::Configuration.profile("Preloading #{model.class.name}##{model.id}") do
|
21
|
+
origin_data = origin_data_for_model(model)
|
22
|
+
origin_data.fetch(:r)[@reflection.name] = model.id
|
23
|
+
|
24
|
+
serializer = ApiMaker::Serializer.new(ability: @ability, args: @args, model: model, select: @select&.dig(model.class))
|
25
|
+
collection_name = serializer.resource.collection_name
|
26
|
+
|
27
|
+
@data.fetch(:included)[collection_name] ||= {}
|
28
|
+
@data.fetch(:included).fetch(collection_name)[model.id] ||= serializer
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
{collection: models}
|
33
|
+
end
|
34
|
+
|
35
|
+
def models
|
36
|
+
@models ||= begin
|
37
|
+
if @reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
38
|
+
query = query_through
|
39
|
+
else
|
40
|
+
query = query_normal
|
41
|
+
end
|
42
|
+
|
43
|
+
query = query.accessible_by(@ability) if @ability
|
44
|
+
query = query.fix
|
45
|
+
query.load
|
46
|
+
query
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def origin_data_for_model(model)
|
51
|
+
origin_id = model.read_attribute("api_maker_origin_id")
|
52
|
+
@data.fetch(:included).fetch(collection_name).fetch(origin_id)
|
53
|
+
end
|
54
|
+
|
55
|
+
def query_through
|
56
|
+
ApiMaker::PreloaderThrough.new(collection: @collection, reflection: @reflection).models_query_through_reflection
|
57
|
+
.select(@reflection.klass.arel_table[Arel.star])
|
58
|
+
.select(@reflection.active_record.arel_table[@reflection.active_record.primary_key].as("api_maker_origin_id"))
|
59
|
+
end
|
60
|
+
|
61
|
+
def query_normal
|
62
|
+
@reflection.klass.where(@reflection.foreign_key => @collection.map(&:id))
|
63
|
+
.select(@reflection.klass.arel_table[Arel.star])
|
64
|
+
.select(@reflection.klass.arel_table[@reflection.foreign_key].as("api_maker_origin_id"))
|
65
|
+
end
|
66
|
+
|
67
|
+
def resource
|
68
|
+
@resource ||= ApiMaker::MemoryStorage.current.resource_for_model(@reflection.klass)
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
class ApiMaker::PreloaderThrough
|
2
|
+
def initialize(collection:, reflection:)
|
3
|
+
@collection = collection
|
4
|
+
@reflection = reflection
|
5
|
+
end
|
6
|
+
|
7
|
+
def models_query_through_reflection
|
8
|
+
last_reflection = @reflection.through_reflection.inverse_of
|
9
|
+
|
10
|
+
if last_reflection
|
11
|
+
table_name = last_reflection.table_name
|
12
|
+
primary_key = last_reflection.klass.primary_key
|
13
|
+
else
|
14
|
+
table_name = @reflection.through_reflection.active_record.model_name.plural
|
15
|
+
primary_key = @reflection.through_reflection.active_record.primary_key
|
16
|
+
end
|
17
|
+
|
18
|
+
joins_hash = joins_array_to_hash(joins_for_reflection(@reflection))
|
19
|
+
|
20
|
+
@reflection.klass.joins(joins_hash)
|
21
|
+
.where(table_name => {primary_key => @collection.map(&:id)})
|
22
|
+
end
|
23
|
+
|
24
|
+
def joins_for_reflection(current_reflection)
|
25
|
+
joins = []
|
26
|
+
|
27
|
+
loop do
|
28
|
+
# Resolve if the through relationship is through multiple other through relationships
|
29
|
+
current_reflection = resolve_through(current_reflection)
|
30
|
+
|
31
|
+
macro = current_reflection.through_reflection.macro
|
32
|
+
inverse_name = current_reflection.through_reflection.__send__(:inverse_name)
|
33
|
+
|
34
|
+
if inverse_name
|
35
|
+
joins << inverse_name
|
36
|
+
elsif macro == :has_many
|
37
|
+
joins << current_reflection.through_reflection.name
|
38
|
+
elsif macro == :belongs_to || macro == :has_one
|
39
|
+
joins << current_reflection.through_reflection.active_record.model_name.plural.to_sym
|
40
|
+
else
|
41
|
+
raise "Unknown class: #{current_reflection.through_reflection.class.name}"
|
42
|
+
end
|
43
|
+
|
44
|
+
current_reflection = next_reflection_for(current_reflection)
|
45
|
+
|
46
|
+
unless current_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
47
|
+
joins.append(append_name_for_current_reflection(current_reflection))
|
48
|
+
break
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
joins
|
53
|
+
end
|
54
|
+
|
55
|
+
def append_name_for_current_reflection(current_reflection)
|
56
|
+
singular_name = current_reflection.__send__(:inverse_name)&.to_s || current_reflection.active_record.model_name.param_key
|
57
|
+
return singular_name.to_sym if @reflection.klass.reflections.key?(singular_name)
|
58
|
+
|
59
|
+
plural_name = singular_name.pluralize
|
60
|
+
return plural_name.to_sym if @reflection.klass.reflections.key?(plural_name)
|
61
|
+
|
62
|
+
raise "Couldn't find a reflection name #{singular_name} or #{plural_name} on #{@reflection.klass.name}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def joins_array_to_hash(array)
|
66
|
+
array = array.clone
|
67
|
+
|
68
|
+
result = {}
|
69
|
+
work_result = result
|
70
|
+
|
71
|
+
while array.any?
|
72
|
+
element = array.pop
|
73
|
+
|
74
|
+
if array.length == 1
|
75
|
+
work_result[element] = array.pop
|
76
|
+
else
|
77
|
+
work_result[element] = {}
|
78
|
+
end
|
79
|
+
|
80
|
+
work_result = work_result[element]
|
81
|
+
end
|
82
|
+
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
def next_reflection_for(current_reflection)
|
87
|
+
reflection_name = (current_reflection.source_reflection_name || @reflection.name).to_s
|
88
|
+
|
89
|
+
new_reflection = current_reflection.through_reflection.klass.reflections[reflection_name.pluralize]
|
90
|
+
new_reflection ||= current_reflection.through_reflection.klass.reflections[reflection_name.singularize]
|
91
|
+
|
92
|
+
raise "No such reflection: #{current_reflection.through_reflection.klass.name}##{reflection_name}" unless new_reflection
|
93
|
+
|
94
|
+
new_reflection
|
95
|
+
end
|
96
|
+
|
97
|
+
def resolve_through(current_reflection)
|
98
|
+
current_reflection = current_reflection.through_reflection while current_reflection.through_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
99
|
+
current_reflection
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class ApiMaker::Railtie < Rails::Railtie
|
2
|
+
initializer "watch routes.json for changes and reload Rails routes if changed" do |app|
|
3
|
+
file_path = Rails.root.join("app", "javascript", "shared", "routes.json")
|
4
|
+
|
5
|
+
reloader = app.config.file_watcher.new([file_path]) do
|
6
|
+
app.reload_routes!
|
7
|
+
end
|
8
|
+
|
9
|
+
app.reloaders << reloader
|
10
|
+
app.reloader.to_run do
|
11
|
+
reloader.execute_if_updated
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class ApiMaker::RelationshipIncluder
|
2
|
+
def self.parse(include_param)
|
3
|
+
if include_param.nil?
|
4
|
+
nil
|
5
|
+
elsif include_param.is_a?(String)
|
6
|
+
ApiMaker::RelationshipIncluder.parse_string(include_param)
|
7
|
+
elsif include_param.is_a?(Array)
|
8
|
+
ApiMaker::RelationshipIncluder.parse_array(include_param)
|
9
|
+
else
|
10
|
+
raise "Unexpected parameter given (#{include_param.class.name}): #{include_param}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.parse_string(include_param)
|
15
|
+
splitted = include_param.split(".")
|
16
|
+
initial = splitted.shift
|
17
|
+
rest = splitted.join(".")
|
18
|
+
{initial => rest}
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.parse_array(include_param)
|
22
|
+
result = {}
|
23
|
+
include_param.each do |include_param_i|
|
24
|
+
parsed = ApiMaker::RelationshipIncluder.parse(include_param_i)
|
25
|
+
parsed.each do |key, value|
|
26
|
+
if result.key?(key)
|
27
|
+
if result[key].is_a?(String)
|
28
|
+
result[key] = [result[key], value]
|
29
|
+
elsif result[key].is_a?(Array)
|
30
|
+
result[key] << value
|
31
|
+
else
|
32
|
+
raise "Unknown object: #{result[key].class.name}"
|
33
|
+
end
|
34
|
+
else
|
35
|
+
result[key] = value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
result
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class ApiMaker::ResourceRouting
|
2
|
+
def self.install_resource_routes(rails_routes, layout: "react", routes: nil)
|
3
|
+
routes ||= JSON.parse(File.read(Rails.root.join("app", "javascript", "shared", "routes.json")))
|
4
|
+
routes.fetch("routes").each do |route|
|
5
|
+
rails_routes.get route.fetch("path") => "#{layout}#show", as: route.fetch("name").to_sym
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class ApiMaker::ResultParser
|
2
|
+
attr_reader :ability, :args
|
3
|
+
|
4
|
+
def self.parse(*args)
|
5
|
+
ApiMaker::ResultParser.new(*args).result
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(object, ability: nil, args: nil, controller: nil)
|
9
|
+
@object = object
|
10
|
+
@ability = ability || controller&.__send__(:current_ability)
|
11
|
+
@args = args || controller&.__send__(:api_maker_args) || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def result
|
15
|
+
parse_object(@object)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def parse_object(object)
|
21
|
+
if object.is_a?(Hash)
|
22
|
+
result = {}
|
23
|
+
object.each do |key, value|
|
24
|
+
result[key] = parse_object(value)
|
25
|
+
end
|
26
|
+
|
27
|
+
result
|
28
|
+
elsif object.is_a?(Array)
|
29
|
+
object.map { |value| parse_object(value) }
|
30
|
+
elsif object.class.name == "Money"
|
31
|
+
{api_maker_type: :money, amount: object.cents, currency: object.currency.iso_code}
|
32
|
+
elsif object.is_a?(Date)
|
33
|
+
object.iso8601
|
34
|
+
elsif object.is_a?(Time)
|
35
|
+
object.utc.iso8601
|
36
|
+
elsif object.is_a?(ApiMaker::CollectionSerializer) || object.is_a?(ApiMaker::Serializer)
|
37
|
+
parse_object(object.as_json)
|
38
|
+
elsif object.is_a?(ActiveRecord::Base)
|
39
|
+
serializer = ApiMaker::Serializer.new(ability: ability, args: args, model: object)
|
40
|
+
|
41
|
+
{
|
42
|
+
api_maker_type: :model,
|
43
|
+
model_name: serializer.resource.collection_name,
|
44
|
+
serialized: parse_object(serializer.as_json)
|
45
|
+
}
|
46
|
+
else
|
47
|
+
object
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
class ApiMaker::Serializer
|
2
|
+
attr_reader :ability, :args, :model
|
3
|
+
|
4
|
+
def self.resource_for(klass)
|
5
|
+
ApiMaker::MemoryStorage.current.resource_for_model(klass)
|
6
|
+
rescue NameError
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.resource_for!(klass)
|
11
|
+
ApiMaker::MemoryStorage.current.resource_for_model(klass)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(ability: nil, args: {}, model:, select: nil)
|
15
|
+
@args = args
|
16
|
+
@model = model
|
17
|
+
@ability = ability
|
18
|
+
@select = select
|
19
|
+
end
|
20
|
+
|
21
|
+
def attributes
|
22
|
+
ApiMaker::Configuration.profile("attributes") do
|
23
|
+
result = {}
|
24
|
+
attributes_to_read.each do |attribute, data|
|
25
|
+
if (if_name = data.dig(:args, :if))
|
26
|
+
condition_result = attribute_value(if_name)
|
27
|
+
next unless condition_result
|
28
|
+
end
|
29
|
+
|
30
|
+
result[attribute] = attribute_value(attribute)
|
31
|
+
end
|
32
|
+
|
33
|
+
result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def attributes_to_read
|
38
|
+
@attributes_to_read ||= @select || resource.default_select
|
39
|
+
end
|
40
|
+
|
41
|
+
def attribute_value(attribute)
|
42
|
+
if resource_instance.respond_to?(attribute)
|
43
|
+
resource_instance.__send__(attribute)
|
44
|
+
else
|
45
|
+
model.__send__(attribute)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def fetch(*args, &blk)
|
50
|
+
result.fetch(*args, &blk)
|
51
|
+
end
|
52
|
+
|
53
|
+
def relationships
|
54
|
+
@relationships ||= {}
|
55
|
+
end
|
56
|
+
|
57
|
+
def resource
|
58
|
+
@resource ||= ApiMaker::MemoryStorage.current.resource_for_model(model.class)
|
59
|
+
end
|
60
|
+
|
61
|
+
def resource_instance
|
62
|
+
@resource_instance ||= resource.new(ability: ability, args: args, model: model)
|
63
|
+
end
|
64
|
+
|
65
|
+
def result
|
66
|
+
@result ||= begin
|
67
|
+
result = {a: attributes}
|
68
|
+
result[:r] = @relationships if @relationships # Only include relationships if set
|
69
|
+
result
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def as_json(_options = nil)
|
74
|
+
result
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_json(_options = nil)
|
78
|
+
JSON.generate(as_json)
|
79
|
+
end
|
80
|
+
|
81
|
+
def inspect
|
82
|
+
"<ApiMaker::Serializer id=\"#{model.id}\" model=\"#{model.class.name}\" relationships=\"#{relationships}\">"
|
83
|
+
end
|
84
|
+
|
85
|
+
alias to_s inspect
|
86
|
+
end
|