encore 0.0.3 → 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.
- checksums.yaml +4 -4
- data/.gitignore +0 -16
- data/.rubocop.yml +53 -0
- data/.travis.yml +10 -2
- data/LICENSE.md +1 -1
- data/README.md +105 -153
- data/Rakefile +10 -0
- data/encore.gemspec +16 -13
- data/gemfiles/{Gemfile.activerecord-3.2.x → Gemfile.activerecord-4.1} +1 -1
- data/lib/encore/config.rb +2 -0
- data/lib/encore/persister/errors_parser.rb +17 -0
- data/lib/encore/persister/instance.rb +85 -0
- data/lib/encore/persister/key_mapping.rb +15 -0
- data/lib/encore/persister/links_parser.rb +57 -0
- data/lib/encore/persister/param_injection.rb +15 -0
- data/lib/encore/serializer/base.rb +48 -0
- data/lib/encore/serializer/eager_loading_manager.rb +11 -0
- data/lib/encore/serializer/instance.rb +56 -0
- data/lib/encore/serializer/linked_resource_manager.rb +19 -0
- data/lib/encore/serializer/links_reflection_includer.rb +50 -0
- data/lib/encore/serializer/main_resource_links_manager/reflection_belongs_to.rb +13 -0
- data/lib/encore/serializer/main_resource_links_manager/reflection_has_many.rb +13 -0
- data/lib/encore/serializer/main_resource_links_manager/reflection_has_one.rb +13 -0
- data/lib/encore/serializer/main_resource_links_manager.rb +45 -0
- data/lib/encore/serializer/main_resource_manager.rb +13 -0
- data/lib/encore/serializer/meta_manager.rb +29 -0
- data/lib/encore/serializer/options_parser.rb +51 -0
- data/lib/encore/serializer/utils.rb +12 -0
- data/lib/encore/version.rb +1 -1
- data/lib/encore.rb +16 -8
- data/spec/encore/persister/belongs_to_links_spec.rb +46 -0
- data/spec/encore/persister/create_resources_spec.rb +55 -0
- data/spec/encore/persister/errors_resources_spec.rb +55 -0
- data/spec/encore/persister/has_many_links_spec.rb +49 -0
- data/spec/encore/persister/has_one_links_spec.rb +49 -0
- data/spec/encore/persister/key_mappings_spec.rb +66 -0
- data/spec/encore/persister/param_injection_spec.rb +46 -0
- data/spec/encore/persister/update_resources_spec.rb +37 -0
- data/spec/encore/serializer/linked/always_include_resources_spec.rb +85 -0
- data/spec/encore/serializer/linked/can_include_resources_spec.rb +69 -0
- data/spec/encore/serializer/linked/linked_resources_spec.rb +103 -0
- data/spec/encore/serializer/links_resource_spec.rb +294 -0
- data/spec/encore/serializer/main_meta_spec.rb +66 -0
- data/spec/encore/serializer/main_resource_spec.rb +37 -0
- data/spec/encore/serializer/no_paging_spec.rb +40 -0
- data/spec/encore_spec.rb +4 -0
- data/spec/spec_helper.rb +8 -21
- data/spec/support/macros/database/database_adapter.rb +9 -0
- data/spec/support/macros/database/sqlite3_adapter.rb +14 -0
- data/spec/support/macros/database_macros.rb +5 -16
- data/spec/support/macros/model_macros.rb +7 -22
- metadata +143 -72
- data/lib/encore/association/has_many_association.rb +0 -12
- data/lib/encore/association/has_one_association.rb +0 -12
- data/lib/encore/association.rb +0 -39
- data/lib/encore/attribute.rb +0 -42
- data/lib/encore/entity/input/associations.rb +0 -27
- data/lib/encore/entity/input/errors.rb +0 -8
- data/lib/encore/entity/input/exposed_attributes.rb +0 -37
- data/lib/encore/entity/input.rb +0 -73
- data/lib/encore/entity/output/json.rb +0 -14
- data/lib/encore/entity/output.rb +0 -13
- data/lib/encore/entity.rb +0 -44
- data/lib/encore/helpers/controller_helper.rb +0 -37
- data/lib/encore/helpers.rb +0 -1
- data/lib/encore/railtie.rb +0 -11
- data/spec/encore/entity/input/associations_spec.rb +0 -48
- data/spec/encore/entity/input/exposed_attributes_spec.rb +0 -46
- data/spec/encore/entity/input_spec.rb +0 -104
- data/spec/encore/entity/output/json_spec.rb +0 -76
- data/spec/encore/entity/output_spec.rb +0 -5
- data/spec/encore/entity_spec.rb +0 -31
- data/spec/encore/helpers/controller_helper_spec.rb +0 -59
@@ -0,0 +1,57 @@
|
|
1
|
+
module Encore
|
2
|
+
module Persister
|
3
|
+
module LinksParser
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def parse_links(args)
|
7
|
+
links = args.delete(:links) || []
|
8
|
+
|
9
|
+
links.each do |link, value|
|
10
|
+
reflection = @model.reflections[link.to_sym]
|
11
|
+
key = fetch_key(reflection)
|
12
|
+
value = fetch_value(value, reflection)
|
13
|
+
|
14
|
+
args.merge!(key => value) if key
|
15
|
+
end
|
16
|
+
|
17
|
+
args
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# `belongs_to` => 'user' become 'user_id'
|
23
|
+
def link_belongs_to(reflection)
|
24
|
+
reflection.foreign_key.to_sym
|
25
|
+
end
|
26
|
+
|
27
|
+
# `has_many` => 'users' become 'user_ids'
|
28
|
+
def link_has_many(reflection)
|
29
|
+
"#{reflection.name.to_s.singularize}_ids".to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
# `has_one` => 'user' stay 'user'
|
33
|
+
def link_has_one(reflection)
|
34
|
+
reflection.name
|
35
|
+
end
|
36
|
+
|
37
|
+
# Convert reflection with the right ActiveRecord key for insert/update.
|
38
|
+
def fetch_key(reflection)
|
39
|
+
case reflection.macro
|
40
|
+
when :belongs_to then link_belongs_to(reflection)
|
41
|
+
when :has_many then link_has_many(reflection)
|
42
|
+
when :has_one then link_has_one(reflection)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Value for `has_one` must be an activerecord instance.
|
47
|
+
# Other reflection macro types stay the same.
|
48
|
+
def fetch_value(value, reflection)
|
49
|
+
if reflection.macro == :has_one
|
50
|
+
reflection.klass.find(value)
|
51
|
+
else
|
52
|
+
value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Encore
|
2
|
+
module Persister
|
3
|
+
module ParamInjection
|
4
|
+
def self.inject(payload, injection)
|
5
|
+
return payload if injection.nil?
|
6
|
+
|
7
|
+
payload.map do |param|
|
8
|
+
injection.reduce(param) do |memo, (key, value)|
|
9
|
+
memo.merge key => value
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'encore/serializer/links_reflection_includer'
|
2
|
+
|
3
|
+
module Encore
|
4
|
+
module Serializer
|
5
|
+
class Base < ::ActiveModel::Serializer
|
6
|
+
def id
|
7
|
+
object.id.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def links
|
11
|
+
object.reflections.each_with_object({}) do |(_, reflection), memo|
|
12
|
+
if object.association(reflection.name).loaded?
|
13
|
+
fetcher = LinksReflectionIncluder::Loaded
|
14
|
+
else
|
15
|
+
next unless self.class.can_access.include?(reflection.name)
|
16
|
+
fetcher = LinksReflectionIncluder::NotLoaded
|
17
|
+
end
|
18
|
+
|
19
|
+
memo.merge!(reflection.name => fetcher.send("reflection_#{reflection.macro}", object, reflection))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Specify which resources the API can be included in the "linked" top-level key.
|
24
|
+
def self.can_include
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Specify which resources the API always include in the "linked" top-level key.
|
29
|
+
def self.always_include
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Specify which resources the API exposes URL to.
|
34
|
+
# Default is can_include + always_include.
|
35
|
+
def self.can_access
|
36
|
+
can_include | always_include
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.root_key
|
40
|
+
model_class.name.pluralize.underscore.to_sym
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.key_mappings
|
44
|
+
{}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'encore/serializer/eager_loading_manager'
|
2
|
+
require 'encore/serializer/linked_resource_manager'
|
3
|
+
require 'encore/serializer/main_resource_manager'
|
4
|
+
require 'encore/serializer/main_resource_links_manager'
|
5
|
+
require 'encore/serializer/meta_manager'
|
6
|
+
require 'encore/serializer/utils'
|
7
|
+
require 'encore/serializer/options_parser'
|
8
|
+
|
9
|
+
module Encore
|
10
|
+
module Serializer
|
11
|
+
class Instance
|
12
|
+
def initialize(collection, opts = {})
|
13
|
+
@collection = collection
|
14
|
+
@serializers = [serializer]
|
15
|
+
@options = parsed_options(opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def as_json(*_)
|
19
|
+
# Prepare main collection
|
20
|
+
@collection = MetaManager.paginate_collection(@collection, @options)
|
21
|
+
@collection = EagerLoadingManager.add(@collection, @options[:include])
|
22
|
+
|
23
|
+
# Fetch linked ids
|
24
|
+
linked_ids = MainResourceLinksManager.add(@collection, reflections, @options[:include])
|
25
|
+
|
26
|
+
# Build final output
|
27
|
+
output = MainResourceManager.add(@collection, serializer)
|
28
|
+
output.merge! linked: LinkedResourceManager.add(linked_ids)
|
29
|
+
output.merge! meta: MetaManager.add(@collection, serializer, @options)
|
30
|
+
|
31
|
+
output
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def reflections
|
37
|
+
@reflections ||= @collection.klass.reflections
|
38
|
+
end
|
39
|
+
|
40
|
+
def serializer
|
41
|
+
@serializer ||= Utils.fetch_serializer(@collection.klass)
|
42
|
+
end
|
43
|
+
|
44
|
+
def parsed_options(opts)
|
45
|
+
parser = OptionsParser.new(opts)
|
46
|
+
|
47
|
+
{
|
48
|
+
include: parser.include(serializer),
|
49
|
+
skip_paging: parser.skip_paging,
|
50
|
+
page: parser.page,
|
51
|
+
per_page: parser.per_page
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'encore/serializer/utils'
|
2
|
+
|
3
|
+
module Encore
|
4
|
+
module Serializer
|
5
|
+
module LinkedResourceManager
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def self.add(linked_ids)
|
9
|
+
linked_ids.reduce({}) do |memo, (model, ids)|
|
10
|
+
klass = model.constantize
|
11
|
+
serializer = Utils.fetch_serializer(klass)
|
12
|
+
|
13
|
+
collection = klass.where(id: ids.to_a)
|
14
|
+
memo.merge! MainResourceManager.add(collection, serializer)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Encore
|
2
|
+
module Serializer
|
3
|
+
module LinksReflectionIncluder
|
4
|
+
module Loaded
|
5
|
+
def self.reflection_belongs_to(object, reflection)
|
6
|
+
object.send(reflection.foreign_key).try(:to_s) if object.respond_to?(reflection.foreign_key)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.reflection_has_one(object, reflection)
|
10
|
+
object.send(reflection.name).try(:id).try(:to_s)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.reflection_has_many(object, reflection)
|
14
|
+
object.send("#{reflection.name.to_s.singularize}_ids").map(&:to_s) if object.send(reflection.name).loaded?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module NotLoaded
|
19
|
+
def self.reflection_has_many(object, reflection)
|
20
|
+
reflection_type = reflection.name.to_s.pluralize
|
21
|
+
|
22
|
+
{
|
23
|
+
href: "/#{reflection_type}?#{object.class.name.downcase}_id=#{object.id}",
|
24
|
+
type: reflection_type
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.reflection_has_one(object, reflection)
|
29
|
+
reflection_type = reflection.name.to_s
|
30
|
+
|
31
|
+
{
|
32
|
+
href: "/#{object.class.name.downcase.pluralize}/#{object.id}/#{reflection_type}",
|
33
|
+
type: reflection_type.pluralize
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.reflection_belongs_to(object, reflection)
|
38
|
+
reflection_type = reflection.name.to_s.pluralize
|
39
|
+
reflection_id = object.send(reflection.foreign_key).try(:to_s)
|
40
|
+
|
41
|
+
{
|
42
|
+
href: "/#{reflection_type}/#{reflection_id}",
|
43
|
+
id: reflection_id,
|
44
|
+
type: reflection_type
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Encore
|
2
|
+
module Serializer
|
3
|
+
module MainResourceLinksManager
|
4
|
+
module ReflectionHasMany
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def self.add(item, reflection)
|
8
|
+
item.send("#{reflection.name.to_s.singularize}_ids").map(&:to_s)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'encore/serializer/main_resource_links_manager/reflection_belongs_to'
|
2
|
+
require 'encore/serializer/main_resource_links_manager/reflection_has_many'
|
3
|
+
require 'encore/serializer/main_resource_links_manager/reflection_has_one'
|
4
|
+
|
5
|
+
module Encore
|
6
|
+
module Serializer
|
7
|
+
module MainResourceLinksManager
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
def self.add(collection, reflections, option_include)
|
11
|
+
collection.each_with_object(Hash.new(Set.new)) do |resource, memo|
|
12
|
+
option_include.each do |inclusion|
|
13
|
+
model, ids = association_collection(resource, inclusion, reflections)
|
14
|
+
memo[model] += ids
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def self.association_collection(item, inclusion, reflections)
|
22
|
+
reflection = reflections[inclusion]
|
23
|
+
class_name = fetch_class_name(item, reflection)
|
24
|
+
|
25
|
+
collection = begin
|
26
|
+
case reflection.macro
|
27
|
+
when :belongs_to then ReflectionBelongsTo.add(item, reflection)
|
28
|
+
when :has_one then ReflectionHasOne.add(item, reflection)
|
29
|
+
when :has_many then ReflectionHasMany.add(item, reflection)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
[class_name, collection.flatten.compact]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.fetch_class_name(item, reflection)
|
37
|
+
if reflection.options[:polymorphic]
|
38
|
+
item.send(reflection.foreign_type).constantize.to_s
|
39
|
+
else
|
40
|
+
reflection.klass.name.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Encore
|
2
|
+
module Serializer
|
3
|
+
module MetaManager
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def self.paginate_collection(collection, options)
|
7
|
+
return collection if options[:skip_paging]
|
8
|
+
|
9
|
+
collection.page(options[:page]).per(options[:per_page])
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.add(collection, serializer, options)
|
13
|
+
return {} if options[:skip_paging]
|
14
|
+
|
15
|
+
{ serializer.root_key => pagination_for(collection) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.pagination_for(collection)
|
19
|
+
{
|
20
|
+
page: collection.current_page,
|
21
|
+
count: collection.total_count,
|
22
|
+
page_count: collection.num_pages,
|
23
|
+
previous_page: collection.prev_page,
|
24
|
+
next_page: collection.next_page
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Encore
|
2
|
+
module Serializer
|
3
|
+
class OptionsParser
|
4
|
+
def initialize(opts)
|
5
|
+
@opts = opts
|
6
|
+
end
|
7
|
+
|
8
|
+
def include(serializer)
|
9
|
+
opt = @opts[:include]
|
10
|
+
|
11
|
+
output = []
|
12
|
+
|
13
|
+
# Split includes list
|
14
|
+
output += opt.split(',').map(&:to_sym) if opt.present?
|
15
|
+
|
16
|
+
# Remove resource type not included in 'can_include'
|
17
|
+
output = serializer.can_include & output if serializer.respond_to?(:can_include)
|
18
|
+
|
19
|
+
# Add 'always_include' resource type
|
20
|
+
output += serializer.always_include if serializer.respond_to?(:always_include)
|
21
|
+
|
22
|
+
output
|
23
|
+
end
|
24
|
+
|
25
|
+
def page
|
26
|
+
opt = @opts[:page]
|
27
|
+
|
28
|
+
opt.present? ? opt.to_i : 1
|
29
|
+
end
|
30
|
+
|
31
|
+
def per_page
|
32
|
+
opt = @opts[:per_page]
|
33
|
+
|
34
|
+
return Kaminari.config.default_per_page if opt.nil?
|
35
|
+
|
36
|
+
max_per_page = Kaminari.config.max_per_page.to_i
|
37
|
+
opt = opt.to_i
|
38
|
+
|
39
|
+
if max_per_page.zero?
|
40
|
+
opt
|
41
|
+
else
|
42
|
+
opt > max_per_page ? max_per_page : opt
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def skip_paging
|
47
|
+
@opts[:skip_paging].present?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Encore
|
2
|
+
module Serializer
|
3
|
+
module Utils
|
4
|
+
def self.fetch_serializer(model)
|
5
|
+
default_serializer = (model.name.gsub('::', '') + 'Serializer')
|
6
|
+
model.active_model_serializer || default_serializer.constantize
|
7
|
+
rescue NameError
|
8
|
+
raise NameError, "can’t find serializer for #{model.name}, try creating #{default_serializer}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/encore/version.rb
CHANGED
data/lib/encore.rb
CHANGED
@@ -1,13 +1,21 @@
|
|
1
1
|
require 'encore/version'
|
2
2
|
|
3
|
-
|
3
|
+
require 'active_model_serializers'
|
4
|
+
require 'active_record'
|
4
5
|
require 'active_support'
|
5
6
|
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
require '
|
7
|
+
# This is a dirty hack to fix dirty code
|
8
|
+
# https://github.com/amatsuda/kaminari/blob/7b049067b143212a172d5bb472184eac23121f34/lib/kaminari.rb#L11-L25
|
9
|
+
oldstderr = $stderr.dup
|
10
|
+
$stderr = StringIO.new
|
11
|
+
require 'kaminari'
|
12
|
+
$stderr = oldstderr
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
+
require 'encore/config'
|
15
|
+
|
16
|
+
require 'encore/serializer/base'
|
17
|
+
require 'encore/serializer/instance'
|
18
|
+
require 'encore/persister/instance'
|
19
|
+
|
20
|
+
module Encore
|
21
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Encore::Persister do
|
4
|
+
let(:persister) { Encore::Persister::Instance }
|
5
|
+
let(:persist!) { persister.new(model, params).persist! }
|
6
|
+
|
7
|
+
before do
|
8
|
+
run_migrations!
|
9
|
+
spawn_models!
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:run_migrations!) do
|
13
|
+
run_migration do
|
14
|
+
create_table(:users, force: true) do |t|
|
15
|
+
t.string :name, default: nil
|
16
|
+
t.integer :project_id, default: nil
|
17
|
+
end
|
18
|
+
create_table(:projects, force: true) do |t|
|
19
|
+
t.string :name, default: nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:spawn_models!) do
|
25
|
+
spawn_model('User') do
|
26
|
+
belongs_to :project
|
27
|
+
end
|
28
|
+
spawn_model('Project')
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:model) { User }
|
32
|
+
let(:project1) { Project.create name: 'a' }
|
33
|
+
|
34
|
+
let(:params) do
|
35
|
+
[{
|
36
|
+
name: 'Allan',
|
37
|
+
links: {
|
38
|
+
project: project1.id.to_s
|
39
|
+
}
|
40
|
+
}]
|
41
|
+
end
|
42
|
+
|
43
|
+
it { expect { persist! }.to change { model.count }.by(1) }
|
44
|
+
it { expect { persist! }.to change { model.first.try(:name) }.to('Allan') }
|
45
|
+
it { expect { persist! }.to change { model.first.try(:project) }.to(project1) }
|
46
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Encore::Persister do
|
4
|
+
let(:persister) { Encore::Persister::Instance }
|
5
|
+
let(:persist!) { persister.new(model, params).persist! }
|
6
|
+
|
7
|
+
let(:run_migrations!) do
|
8
|
+
run_migration do
|
9
|
+
create_table(:users, force: true) do |t|
|
10
|
+
t.string :name, default: nil
|
11
|
+
t.string :phone, default: nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:spawn_models!) do
|
17
|
+
spawn_model('User')
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:model) { User }
|
21
|
+
|
22
|
+
before do
|
23
|
+
run_migrations!
|
24
|
+
spawn_models!
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'single create' do
|
28
|
+
let(:params) do
|
29
|
+
[{
|
30
|
+
name: 'Allan',
|
31
|
+
phone: '555-2525'
|
32
|
+
}]
|
33
|
+
end
|
34
|
+
|
35
|
+
it { expect { persist! }.to change { model.count }.by(1) }
|
36
|
+
it { expect { persist! }.to change { model.first.try(:name) }.to('Allan') }
|
37
|
+
it { expect { persist! }.to change { model.first.try(:phone) }.to('555-2525') }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'many create' do
|
41
|
+
let(:params) do
|
42
|
+
[{
|
43
|
+
name: 'Allan',
|
44
|
+
phone: '555-2525'
|
45
|
+
}, {
|
46
|
+
name: 'Bob'
|
47
|
+
}]
|
48
|
+
end
|
49
|
+
|
50
|
+
it { expect { persist! }.to change { model.count }.by(2) }
|
51
|
+
it { expect { persist! }.to change { model.first.try(:name) }.to('Allan') }
|
52
|
+
it { expect { persist! }.to change { model.first.try(:phone) }.to('555-2525') }
|
53
|
+
it { expect { persist! }.to change { model.last.try(:name) }.to('Bob') }
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Encore::Persister do
|
4
|
+
let(:persister) { Encore::Persister::Instance.new(model, params) }
|
5
|
+
let(:persist!) { persister.persist! }
|
6
|
+
|
7
|
+
let(:run_migrations!) do
|
8
|
+
run_migration do
|
9
|
+
create_table(:users, force: true) do |t|
|
10
|
+
t.string :name, default: nil
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:spawn_models!) do
|
16
|
+
spawn_model('User') do
|
17
|
+
validates :name, presence: true, length: { minimum: 2 }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
before do
|
22
|
+
run_migrations!
|
23
|
+
spawn_models!
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:params) do
|
27
|
+
[{
|
28
|
+
name: ''
|
29
|
+
}]
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:expected_error) do
|
33
|
+
{
|
34
|
+
field: 'name',
|
35
|
+
types: ['can\'t be blank', 'is too short (minimum is 2 characters)'],
|
36
|
+
path: 'user/0/name'
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'create' do
|
41
|
+
let(:model) { User }
|
42
|
+
|
43
|
+
it { expect { persist! }.to_not change { model.count } }
|
44
|
+
it { expect { persist! }.to change { persister.errors.count }.to(1) }
|
45
|
+
it { expect { persist! }.to change { persister.errors.first }.to(expected_error) }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'update' do
|
49
|
+
let(:model) { User.create name: 'Robert' }
|
50
|
+
|
51
|
+
it { expect { persist! }.to_not change { model.reload.name } }
|
52
|
+
it { expect { persist! }.to change { persister.errors.count }.to(1) }
|
53
|
+
it { expect { persist! }.to change { persister.errors.first }.to(expected_error) }
|
54
|
+
end
|
55
|
+
end
|