encore 0.0.3 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|