api_me 0.9.4 → 0.10.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/Rakefile +16 -39
- data/lib/api_me.rb +12 -10
- data/lib/api_me/base_filter.rb +2 -0
- data/lib/api_me/engine.rb +5 -0
- data/lib/api_me/model.rb +2 -0
- data/lib/api_me/pagination.rb +28 -11
- data/lib/api_me/sorting.rb +24 -11
- data/lib/api_me/version.rb +3 -1
- data/lib/generators/api_me/controller/controller_generator.rb +8 -6
- data/lib/generators/api_me/filter/filter_generator.rb +2 -0
- data/lib/generators/api_me/install_generator.rb +2 -0
- data/lib/generators/api_me/policy/policy_generator.rb +2 -0
- data/lib/generators/api_me/resource/resource_generator.rb +2 -0
- metadata +25 -92
- data/.editorconfig +0 -41
- data/.gitignore +0 -3
- data/.rubocop.yml +0 -8
- data/.ruby-version +0 -1
- data/.travis.yml +0 -4
- data/Gemfile +0 -11
- data/Gemfile.lock +0 -153
- data/LICENSE +0 -20
- data/README.md +0 -194
- data/api_me.gemspec +0 -33
- data/config.ru +0 -7
- data/spec/acceptance/api/v1/fails_spec.rb +0 -12
- data/spec/acceptance/api/v1/posts_spec.rb +0 -154
- data/spec/acceptance/api/v1/users_spec.rb +0 -96
- data/spec/acceptance/multi_word_resource_spec.rb +0 -12
- data/spec/internal/app/controllers/api/v1/fails_controller.rb +0 -11
- data/spec/internal/app/controllers/api/v1/multi_word_resources_controller.rb +0 -6
- data/spec/internal/app/controllers/api/v1/posts_controller.rb +0 -3
- data/spec/internal/app/controllers/api/v1/users_controller.rb +0 -3
- data/spec/internal/app/controllers/application_controller.rb +0 -12
- data/spec/internal/app/filters/user_filter.rb +0 -7
- data/spec/internal/app/models/post.rb +0 -3
- data/spec/internal/app/models/test_model.rb +0 -21
- data/spec/internal/app/models/user.rb +0 -3
- data/spec/internal/app/policies/application_policy.rb +0 -65
- data/spec/internal/app/policies/post_policy.rb +0 -4
- data/spec/internal/app/policies/test_model_policy.rb +0 -5
- data/spec/internal/app/policies/user_policy.rb +0 -8
- data/spec/internal/app/serializers/post_serializer.rb +0 -5
- data/spec/internal/app/serializers/test_model_serializer.rb +0 -5
- data/spec/internal/app/serializers/user_serializer.rb +0 -3
- data/spec/internal/config/database.yml +0 -3
- data/spec/internal/config/initializers/active_model_serializers.rb +0 -1
- data/spec/internal/config/routes.rb +0 -10
- data/spec/internal/db/schema.rb +0 -12
- data/spec/internal/log/.gitignore +0 -1
- data/spec/internal/public/favicon.ico +0 -0
- data/spec/spec_helper.rb +0 -24
data/api_me.gemspec
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
lib = File.expand_path('../lib', __FILE__)
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require 'api_me/version'
|
6
|
-
|
7
|
-
Gem::Specification.new do |s|
|
8
|
-
s.name = 'api_me'
|
9
|
-
s.version = ApiMe::VERSION
|
10
|
-
s.authors = ['Sam Clopton', 'Joe Weakley']
|
11
|
-
s.email = ['samsinite@gmail.com']
|
12
|
-
s.homepage = 'https://github.com/wildland/api_me'
|
13
|
-
s.summary = 'Api Me'
|
14
|
-
s.description = "This friendly library gives you helpers and generators to assist building RESTful API's in your Rails app."
|
15
|
-
s.license = 'MIT'
|
16
|
-
|
17
|
-
s.files = `git ls-files`.split("\n")
|
18
|
-
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
19
|
-
s.require_paths = %w(lib app)
|
20
|
-
|
21
|
-
s.add_runtime_dependency 'activerecord', '>= 4.1.16'
|
22
|
-
s.add_runtime_dependency 'activesupport', '>= 4.1.16'
|
23
|
-
s.add_runtime_dependency 'pundit', '~> 1.1.0'
|
24
|
-
s.add_runtime_dependency 'active_model_serializers', '~> 0.10.0'
|
25
|
-
s.add_runtime_dependency 'search_object', '~> 1.0'
|
26
|
-
s.add_runtime_dependency 'kaminari', '~> 0.16.3'
|
27
|
-
|
28
|
-
s.add_development_dependency 'combustion', '~> 0.5.1'
|
29
|
-
s.add_development_dependency 'rspec-rails', '~> 3'
|
30
|
-
s.add_development_dependency 'sqlite3', '~> 1.3.7'
|
31
|
-
s.add_development_dependency 'rubocop', '~> 0.49'
|
32
|
-
s.add_development_dependency 'rake-notes', '>= 0.2.0'
|
33
|
-
end
|
data/config.ru
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Posts API' do
|
4
|
-
it 'sends the list of posts using the default filter' do
|
5
|
-
posts = [
|
6
|
-
Post.create(name: 'test'),
|
7
|
-
Post.create(name: 'test 2')
|
8
|
-
]
|
9
|
-
|
10
|
-
get '/api/v1/posts'
|
11
|
-
|
12
|
-
expect(last_response.status).to eq(200)
|
13
|
-
json = JSON.parse(last_response.body)
|
14
|
-
|
15
|
-
expect(json['posts'].length).to eq(posts.count)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'is paging with page offset using default page size and restricting size' do
|
19
|
-
40.times do
|
20
|
-
Post.create(name: 'page item')
|
21
|
-
end
|
22
|
-
|
23
|
-
get '/api/v1/posts?page%5Boffset%5D=1'
|
24
|
-
json = JSON.parse(last_response.body)
|
25
|
-
expect(json['posts'].length).to eq(25)
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'is page offset of 2 working for size of 40 default page size of 25' do
|
29
|
-
40.times do
|
30
|
-
Post.create(name: 'page item')
|
31
|
-
end
|
32
|
-
|
33
|
-
get '/api/v1/posts?page%5Boffset%5D=2'
|
34
|
-
json = JSON.parse(last_response.body)
|
35
|
-
expect(json['posts'].length).to eq(15)
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'is page offset of -1 working for size of 40 default page size of 25' do
|
39
|
-
# min page offset is 1, anything less gets converted to 1 and results in page size records
|
40
|
-
40.times do
|
41
|
-
Post.create(name: 'page item')
|
42
|
-
end
|
43
|
-
|
44
|
-
get '/api/v1/posts?page%5Boffset%5D=-1'
|
45
|
-
json = JSON.parse(last_response.body)
|
46
|
-
expect(json['posts'].length).to eq(25)
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'is page offset of 3 working for size of 40 default page size of 25' do
|
50
|
-
# overflow on page offset will result in 0 records
|
51
|
-
40.times do
|
52
|
-
Post.create(name: 'page item')
|
53
|
-
end
|
54
|
-
|
55
|
-
get '/api/v1/posts?page%5Boffset%5D=3'
|
56
|
-
json = JSON.parse(last_response.body)
|
57
|
-
expect(json['posts'].length).to eq(0)
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'is page size of 10 working for default offset of 1' do
|
61
|
-
# overflow on page offset will result in 0 records
|
62
|
-
40.times do
|
63
|
-
Post.create(name: 'page item')
|
64
|
-
end
|
65
|
-
|
66
|
-
get '/api/v1/posts?page%5Bsize%5D=10'
|
67
|
-
json = JSON.parse(last_response.body)
|
68
|
-
expect(json['posts'].length).to eq(10)
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'is page size working when the value is negative' do
|
72
|
-
# overflow on page offset will result in 0 records
|
73
|
-
40.times do
|
74
|
-
Post.create(name: 'page item')
|
75
|
-
end
|
76
|
-
|
77
|
-
get '/api/v1/posts?page%5Bsize%5D=-10'
|
78
|
-
json = JSON.parse(last_response.body)
|
79
|
-
expect(json['posts'].length).to eq(25)
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'is page size working when the value is higher than the total record count' do
|
83
|
-
# overflow on page offset will result in 0 records
|
84
|
-
40.times do
|
85
|
-
Post.create(name: 'page item')
|
86
|
-
end
|
87
|
-
|
88
|
-
get '/api/v1/posts?page%5Bsize%5D=100'
|
89
|
-
json = JSON.parse(last_response.body)
|
90
|
-
expect(json['posts'].length).to eq(40)
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'is the result all records when no page paramas are sent' do
|
94
|
-
# overflow on page offset will result in 0 records
|
95
|
-
100.times do
|
96
|
-
Post.create(name: 'page item')
|
97
|
-
end
|
98
|
-
|
99
|
-
get '/api/v1/posts'
|
100
|
-
json = JSON.parse(last_response.body)
|
101
|
-
expect(json['posts'].length).to eq(100)
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'restricts page_size when max_per_page config is less' do
|
105
|
-
100.times do
|
106
|
-
Post.create(name: 'page item')
|
107
|
-
end
|
108
|
-
|
109
|
-
Kaminari.config.max_per_page = 10
|
110
|
-
|
111
|
-
get '/api/v1/posts?page%5Bsize%5D=100'
|
112
|
-
json = JSON.parse(last_response.body)
|
113
|
-
expect(json['posts'].length).to eq(10)
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'sends posts filtered by ids' do
|
117
|
-
all_posts = [
|
118
|
-
Post.create(name: 'test'),
|
119
|
-
Post.create(name: 'test 2'),
|
120
|
-
Post.create(name: 'test 3')
|
121
|
-
]
|
122
|
-
|
123
|
-
filtered_posts = [all_posts[0], all_posts[2]]
|
124
|
-
|
125
|
-
get '/api/v1/posts?ids%5B%5D=' + filtered_posts[0].id.to_s +
|
126
|
-
'&ids%5B%5D=' + filtered_posts[1].id.to_s
|
127
|
-
|
128
|
-
expect(last_response.status).to eq(200)
|
129
|
-
json = JSON.parse(last_response.body)
|
130
|
-
|
131
|
-
expect(json['posts'].length).to eq(filtered_posts.count)
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'sends posts reverse sorted by id' do
|
135
|
-
20.times do |i|
|
136
|
-
Post.create(name: 'Post' + i.to_s)
|
137
|
-
end
|
138
|
-
|
139
|
-
get '/api/v1/posts?sort%5Bcriteria%5D=id&sort%5Breverse%5D=true'
|
140
|
-
json = JSON.parse(last_response.body)
|
141
|
-
expect(json['posts'].last['name']).to eq('Post0')
|
142
|
-
end
|
143
|
-
|
144
|
-
it 'sends posts reverse sorted by id and paginated with a size of 10 and an offset of 1' do
|
145
|
-
20.times do |i|
|
146
|
-
Post.create(name: 'Post' + i.to_s)
|
147
|
-
end
|
148
|
-
|
149
|
-
get '/api/v1/posts?page%5Boffset%5D=1&page%5Bsize%5D=10&sort%5Bcriteria%5D=id&sort%5Breverse%5D=true'
|
150
|
-
json = JSON.parse(last_response.body)
|
151
|
-
expect(json['posts'].first['name']).to eq('Post19')
|
152
|
-
expect(json['posts'].length).to eq(10)
|
153
|
-
end
|
154
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Users API' do
|
4
|
-
it 'sends the list of users' do
|
5
|
-
users = [
|
6
|
-
User.create(username: 'Test'),
|
7
|
-
User.create(username: 'Test 2')
|
8
|
-
]
|
9
|
-
|
10
|
-
get '/api/v1/users'
|
11
|
-
|
12
|
-
expect(last_response.status).to eq(200)
|
13
|
-
json = JSON.parse(last_response.body)
|
14
|
-
|
15
|
-
expect(json['users'].length).to eq(users.count)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'returns a 404 for a user that does not exist' do
|
19
|
-
invalid_user_id = User.maximum(:id).to_i + 1
|
20
|
-
|
21
|
-
get '/api/v1/users/' + invalid_user_id.to_s + '/'
|
22
|
-
|
23
|
-
expect(last_response.status).to eq(404)
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'returns a 404 for new' do
|
27
|
-
|
28
|
-
get '/api/v1/users/new'
|
29
|
-
|
30
|
-
expect(last_response.status).to eq(404)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'returns a 404 for edit' do
|
34
|
-
user = User.create(username: 'Foo')
|
35
|
-
|
36
|
-
expect(user.username).to eq('Foo')
|
37
|
-
|
38
|
-
get '/api/v1/users/' + user.id.to_s + '/edit'
|
39
|
-
|
40
|
-
expect(last_response.status).to eq(404)
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'creates a new user' do
|
44
|
-
user_params = {
|
45
|
-
username: 'Test'
|
46
|
-
}
|
47
|
-
|
48
|
-
post '/api/v1/users/', user: user_params
|
49
|
-
|
50
|
-
expect(last_response.status).to eq(201)
|
51
|
-
json = JSON.parse(last_response.body)
|
52
|
-
|
53
|
-
expect(json['user']['username']).to eq(user_params[:username])
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'updates an existing user' do
|
57
|
-
user = User.create(username: 'Foo')
|
58
|
-
|
59
|
-
expect(user.username).to eq('Foo')
|
60
|
-
|
61
|
-
put '/api/v1/users/' + user.id.to_s + '/', user: { username: 'Bar' }
|
62
|
-
|
63
|
-
updated_user = User.find(user.id)
|
64
|
-
expect(last_response.status).to eq(204)
|
65
|
-
expect(updated_user.username).to eq('Bar')
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'destroys an existing user' do
|
69
|
-
user = User.create(username: 'Foo')
|
70
|
-
|
71
|
-
expect(user.id).to_not eq(nil)
|
72
|
-
|
73
|
-
delete '/api/v1/users/' + user.id.to_s + '/'
|
74
|
-
|
75
|
-
does_user_exist = User.where(id: user.id).exists?
|
76
|
-
expect(last_response.status).to eq(204)
|
77
|
-
expect(does_user_exist).to eq(false)
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'sends a filtered list of users' do
|
81
|
-
all_users = [
|
82
|
-
User.create(username: 'Test'),
|
83
|
-
User.create(username: 'Demo'),
|
84
|
-
User.create(username: 'Test 2')
|
85
|
-
]
|
86
|
-
|
87
|
-
filtered_users = [all_users[0], all_users[2]]
|
88
|
-
|
89
|
-
get '/api/v1/users?filters%5Bsearch%5D=Test'
|
90
|
-
|
91
|
-
expect(last_response.status).to eq(200)
|
92
|
-
json = JSON.parse(last_response.body)
|
93
|
-
|
94
|
-
expect(json['users'].length).to eq(filtered_users.count)
|
95
|
-
end
|
96
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'multi-word API resource' do
|
4
|
-
it 'succeeds creating a new object using a resource that consists of multiple words' do
|
5
|
-
post '/api/v1/multi_word_resources', test_model: { test: true }
|
6
|
-
|
7
|
-
expect(last_response.status).to eq(201)
|
8
|
-
json = JSON.parse(last_response.body)
|
9
|
-
|
10
|
-
expect(json['test_model']['created']).to eq(true)
|
11
|
-
end
|
12
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
class ApplicationController < ActionController::Base
|
2
|
-
# Prevent CSRF attacks by raising an exception.
|
3
|
-
# For APIs, you may want to use :null_session instead.
|
4
|
-
protect_from_forgery with: :exception
|
5
|
-
|
6
|
-
private
|
7
|
-
|
8
|
-
# Needed by pundit
|
9
|
-
def current_user
|
10
|
-
nil
|
11
|
-
end
|
12
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'active_model_serializers/model'
|
2
|
-
|
3
|
-
class TestModel < ActiveModelSerializers::Model
|
4
|
-
def self.create
|
5
|
-
@created = true
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.created
|
9
|
-
@created ||= false
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(*_args); end
|
13
|
-
|
14
|
-
def save!(*_args)
|
15
|
-
TestModel.create
|
16
|
-
end
|
17
|
-
|
18
|
-
def created
|
19
|
-
TestModel.created
|
20
|
-
end
|
21
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
class ApplicationPolicy
|
2
|
-
attr_reader :user, :record
|
3
|
-
|
4
|
-
def initialize(user, record)
|
5
|
-
@user = user
|
6
|
-
@record = record
|
7
|
-
end
|
8
|
-
|
9
|
-
def index?
|
10
|
-
true
|
11
|
-
end
|
12
|
-
|
13
|
-
def show?
|
14
|
-
scope.where(id: record.id).exists?
|
15
|
-
end
|
16
|
-
|
17
|
-
def create?
|
18
|
-
true
|
19
|
-
end
|
20
|
-
|
21
|
-
def new?
|
22
|
-
create?
|
23
|
-
end
|
24
|
-
|
25
|
-
def update?
|
26
|
-
true
|
27
|
-
end
|
28
|
-
|
29
|
-
def edit?
|
30
|
-
update?
|
31
|
-
end
|
32
|
-
|
33
|
-
def destroy?
|
34
|
-
true
|
35
|
-
end
|
36
|
-
|
37
|
-
def scope
|
38
|
-
Pundit.policy_scope!(user, record.class)
|
39
|
-
end
|
40
|
-
|
41
|
-
class Scope
|
42
|
-
attr_reader :user, :scope
|
43
|
-
|
44
|
-
def initialize(user, scope)
|
45
|
-
@user = user
|
46
|
-
@scope = scope
|
47
|
-
end
|
48
|
-
|
49
|
-
def resolve
|
50
|
-
readable
|
51
|
-
end
|
52
|
-
|
53
|
-
def readable
|
54
|
-
scope
|
55
|
-
end
|
56
|
-
|
57
|
-
def modifyable
|
58
|
-
scope
|
59
|
-
end
|
60
|
-
|
61
|
-
def destroyable
|
62
|
-
scope
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|