rails_curd_base 0.1.2 → 0.1.3
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/README.md +35 -12
- data/app/controllers/rails_curd_base/curd_controller.rb +58 -6
- data/lib/rails_curd_base/version.rb +1 -1
- data/llms.txt +47 -48
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9bc05a5c466ae239abb14e9c208cc888d1c0c5c0926e1d8e6060dbbae4bd5b48
|
|
4
|
+
data.tar.gz: 205db1b08586497ffa8f56de1f8c763a335d298cd20662338f227fd799b02e29
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: da7a3353202628ddf30765e3bc4c9b0309ba30345e75b2d880ba9c3da2bd444ab3e9cefd7ef61d9dfa92f4a50638f9b026664f9d8d8865cb26013098bb004304
|
|
7
|
+
data.tar.gz: fd0f70f3ffd9483eb1cdf2418ff8561e7b548e7aac861a7c5e884059195afe485a2db7bdf68141ebc823462d6439529f3a4020544d6d3cca25989690405334f2
|
data/README.md
CHANGED
|
@@ -186,6 +186,40 @@ DELETE /api/posts/1
|
|
|
186
186
|
|
|
187
187
|
## 高级用法
|
|
188
188
|
|
|
189
|
+
### 自定义数据范围
|
|
190
|
+
```ruby
|
|
191
|
+
class Api::PostsController < RailsCurdBase::CurdController
|
|
192
|
+
# 只返回当前用户的文章
|
|
193
|
+
def collection
|
|
194
|
+
current_user.posts
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 字段过滤
|
|
200
|
+
|
|
201
|
+
**配置不同 action 返回不同字段**:
|
|
202
|
+
```ruby
|
|
203
|
+
class Api::PostsController < RailsCurdBase::CurdController
|
|
204
|
+
# index 只返回部分字段
|
|
205
|
+
index_fields :id, :title, :created_at
|
|
206
|
+
|
|
207
|
+
# show 返回完整字段
|
|
208
|
+
show_fields :id, :title, :content, :status, :created_at, :updated_at
|
|
209
|
+
end
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**动态指定返回字段(通过 URL 参数)**:
|
|
213
|
+
```bash
|
|
214
|
+
# 只返回 id 和 title
|
|
215
|
+
GET /api/posts?fields=id,title
|
|
216
|
+
|
|
217
|
+
# 只返回 id, title, created_at
|
|
218
|
+
GET /api/posts/1?fields=id,title,created_at
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**优先级**:URL 参数 > Action 配置 > 全部字段
|
|
222
|
+
|
|
189
223
|
### 生命周期钩子
|
|
190
224
|
|
|
191
225
|
```ruby
|
|
@@ -219,17 +253,6 @@ class Api::PostsController < RailsCurdBase::CurdController
|
|
|
219
253
|
end
|
|
220
254
|
```
|
|
221
255
|
|
|
222
|
-
### 自定义数据范围
|
|
223
|
-
|
|
224
|
-
```ruby
|
|
225
|
-
class Api::PostsController < RailsCurdBase::CurdController
|
|
226
|
-
# 只返回当前用户的文章
|
|
227
|
-
def collection
|
|
228
|
-
current_user.posts
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
```
|
|
232
|
-
|
|
233
256
|
### 嵌套资源
|
|
234
257
|
|
|
235
258
|
```ruby
|
|
@@ -240,7 +263,7 @@ class Api::UserPostsController < RailsCurdBase::CurdController
|
|
|
240
263
|
end
|
|
241
264
|
```
|
|
242
265
|
|
|
243
|
-
###
|
|
266
|
+
### 完全自定义序列化
|
|
244
267
|
|
|
245
268
|
```ruby
|
|
246
269
|
class Api::PostsController < RailsCurdBase::CurdController
|
|
@@ -5,13 +5,33 @@ module RailsCurdBase
|
|
|
5
5
|
# === CRUD 基础动作 ===
|
|
6
6
|
before_action :set_resource, only: %i[show update destroy]
|
|
7
7
|
|
|
8
|
+
class << self
|
|
9
|
+
# 配置 index 操作显示的字段
|
|
10
|
+
def index_fields(*fields)
|
|
11
|
+
@index_fields = fields
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# 配置 show 操作显示的字段
|
|
15
|
+
def show_fields(*fields)
|
|
16
|
+
@show_fields = fields
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def get_index_fields
|
|
20
|
+
@index_fields
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def get_show_fields
|
|
24
|
+
@show_fields
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
8
28
|
def index
|
|
9
29
|
result = apply_query_with_meta(collection)
|
|
10
30
|
data = {
|
|
11
31
|
query_config[:meta][:rows_key] => serialize_collection(result[:collection]),
|
|
12
32
|
}
|
|
13
33
|
data.merge!(result[:meta]) if result[:meta]
|
|
14
|
-
ok data: data
|
|
34
|
+
ok data: data
|
|
15
35
|
end
|
|
16
36
|
|
|
17
37
|
def show
|
|
@@ -24,7 +44,7 @@ module RailsCurdBase
|
|
|
24
44
|
if before_save(@resource) && @resource.save
|
|
25
45
|
after_save(@resource)
|
|
26
46
|
data = serialize_resource(@resource)
|
|
27
|
-
ok data: data,
|
|
47
|
+
ok data: data, code: 201
|
|
28
48
|
else
|
|
29
49
|
fail message: "Validation failed", code: 422, data: { errors: @resource.errors.full_messages }
|
|
30
50
|
end
|
|
@@ -34,7 +54,7 @@ module RailsCurdBase
|
|
|
34
54
|
if before_save(resource) && resource.update(resource_params)
|
|
35
55
|
after_save(resource)
|
|
36
56
|
data = serialize_resource(resource)
|
|
37
|
-
ok data: data
|
|
57
|
+
ok data: data
|
|
38
58
|
else
|
|
39
59
|
fail message: "Validation failed", code: 422, data: { errors: resource.errors.full_messages }
|
|
40
60
|
end
|
|
@@ -58,18 +78,50 @@ module RailsCurdBase
|
|
|
58
78
|
|
|
59
79
|
def destroy
|
|
60
80
|
resource.destroy
|
|
61
|
-
ok
|
|
81
|
+
ok code: 204
|
|
62
82
|
end
|
|
63
83
|
|
|
64
84
|
private
|
|
65
85
|
|
|
66
86
|
# === 序列化逻辑 ===
|
|
67
87
|
def serialize_resource(resource)
|
|
68
|
-
resource.as_json
|
|
88
|
+
data = resource.as_json
|
|
89
|
+
|
|
90
|
+
# 优先级: 请求参数 > action 配置
|
|
91
|
+
fields = requested_fields || fields_for_action(action_name)
|
|
92
|
+
filter_fields(data, fields) if fields
|
|
93
|
+
data
|
|
69
94
|
end
|
|
70
95
|
|
|
71
96
|
def serialize_collection(collection)
|
|
72
|
-
collection.
|
|
97
|
+
collection.map do |resource|
|
|
98
|
+
serialize_resource(resource)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# 从请求参数获取指定字段
|
|
103
|
+
def requested_fields
|
|
104
|
+
return nil unless params[:fields].present?
|
|
105
|
+
|
|
106
|
+
params[:fields].split(',').map(&:to_sym)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# 根据 action 获取配置的字段
|
|
110
|
+
def fields_for_action(action)
|
|
111
|
+
case action
|
|
112
|
+
when 'index'
|
|
113
|
+
self.class.get_index_fields
|
|
114
|
+
when 'show'
|
|
115
|
+
self.class.get_show_fields
|
|
116
|
+
else
|
|
117
|
+
nil
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# 过滤字段
|
|
122
|
+
def filter_fields(data, fields)
|
|
123
|
+
fields_sym = fields.map(&:to_sym)
|
|
124
|
+
data.select! { |key, _| fields_sym.include?(key.to_sym) }
|
|
73
125
|
end
|
|
74
126
|
|
|
75
127
|
# === 资源推导 ===
|
data/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# RailsCurdBase - AI Assistant Guide
|
|
2
2
|
|
|
3
|
-
> RailsCurdBase is a Ruby on Rails CRUD base controller gem providing ready-to-use Create, Read, Update, Delete functionality with advanced query capabilities including pagination, sorting, searching, and filtering. It
|
|
3
|
+
> RailsCurdBase is a Ruby on Rails CRUD base controller gem providing ready-to-use Create, Read, Update, Delete functionality with advanced query capabilities including pagination, sorting, searching, and filtering. It uses RailsWarp for unified JSON responses and Kaminari for pagination.
|
|
4
4
|
|
|
5
5
|
**IMPORTANT NOTES FOR AI ASSISTANTS:**
|
|
6
6
|
- RailsCurdBase inherits from ActionController::API for Rails API applications
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
- Built-in Queryable concern provides pagination, sorting, searching, filtering
|
|
10
10
|
- Four lifecycle hooks: before_create, after_create, before_update, after_update
|
|
11
11
|
- Resource automatically derived: controller_name.singularize.classify.constantize
|
|
12
|
+
- Success responses use default "success" message from RailsWarp (no custom message)
|
|
13
|
+
- Error responses keep custom messages ("Validation failed", "Record not found")
|
|
12
14
|
|
|
13
15
|
## DOCUMENTATION LINKS
|
|
14
16
|
|
|
15
|
-
- Repository: https://github.com/
|
|
17
|
+
- Repository: https://github.com/aferic/rails_curd_base
|
|
16
18
|
- Usage Guide: test/dummy/EXAMPLE_USAGE.md (complete API documentation and examples)
|
|
17
19
|
- Test/Demo App: test/dummy/ directory (fully working example)
|
|
18
20
|
|
|
@@ -20,7 +22,7 @@
|
|
|
20
22
|
|
|
21
23
|
### 1. Zero-Configuration CRUD
|
|
22
24
|
Inherit from CurdController to get complete CRUD:
|
|
23
|
-
- index: List with pagination, sorting, searching, filtering
|
|
25
|
+
- index: List with query capabilities (pagination, sorting, searching, filtering)
|
|
24
26
|
- show: Single record retrieval
|
|
25
27
|
- create: Create new records
|
|
26
28
|
- update: Update existing records
|
|
@@ -28,13 +30,13 @@ Inherit from CurdController to get complete CRUD:
|
|
|
28
30
|
|
|
29
31
|
### 2. Queryable Module (supports_query)
|
|
30
32
|
Configure via supports_query:
|
|
31
|
-
- Pagination
|
|
32
|
-
- Sorting
|
|
33
|
-
- Searching
|
|
34
|
-
- Filtering
|
|
33
|
+
- **Pagination**: page, size parameters (Kaminari)
|
|
34
|
+
- **Sorting**: sort parameter (supports -field for desc)
|
|
35
|
+
- **Searching**: q parameter (multi-field LIKE search)
|
|
36
|
+
- **Filtering**: filter parameter (eq, neq, gt, gte, lt, lte, in, nin operators)
|
|
35
37
|
|
|
36
38
|
### 3. Unified Response Format (RailsWarp)
|
|
37
|
-
- ok: success response with data,
|
|
39
|
+
- ok: success response with data, code
|
|
38
40
|
- fail: error response with message, code, errors data
|
|
39
41
|
|
|
40
42
|
### 4. Lifecycle Hooks
|
|
@@ -82,33 +84,35 @@ GET /api/posts?page=1&size=10&sort=-created_at&q=rails&filter[status]=published
|
|
|
82
84
|
# Show single
|
|
83
85
|
GET /api/posts/1
|
|
84
86
|
|
|
85
|
-
# Create
|
|
87
|
+
# Create (flat format - recommended)
|
|
88
|
+
POST /api/posts
|
|
89
|
+
{"title": "Hello", "content": "World", "status": "published"}
|
|
90
|
+
|
|
91
|
+
# Create (nested format - also supported)
|
|
86
92
|
POST /api/posts
|
|
87
93
|
{"post": {"title": "Hello", "content": "World", "status": "published"}}
|
|
88
94
|
|
|
89
|
-
# Update
|
|
95
|
+
# Update (flat format - recommended)
|
|
90
96
|
PUT /api/posts/1
|
|
91
|
-
{"
|
|
97
|
+
{"title": "Updated"}
|
|
92
98
|
|
|
93
99
|
# Delete
|
|
94
100
|
DELETE /api/posts/1
|
|
95
101
|
```
|
|
96
102
|
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
## RESPONSE FORMAT
|
|
104
|
+
|
|
105
|
+
### Success Response
|
|
99
106
|
```json
|
|
100
107
|
{
|
|
101
108
|
"success": true,
|
|
102
109
|
"code": 200,
|
|
103
|
-
"msg": "
|
|
104
|
-
"data": {
|
|
105
|
-
"rows": [...],
|
|
106
|
-
"total": 100
|
|
107
|
-
}
|
|
110
|
+
"msg": "success",
|
|
111
|
+
"data": { ... }
|
|
108
112
|
}
|
|
109
113
|
```
|
|
110
114
|
|
|
111
|
-
Error
|
|
115
|
+
### Error Response
|
|
112
116
|
```json
|
|
113
117
|
{
|
|
114
118
|
"success": false,
|
|
@@ -169,15 +173,18 @@ supports_query(
|
|
|
169
173
|
filter_param: :filter
|
|
170
174
|
}
|
|
171
175
|
)
|
|
172
|
-
# Usage:
|
|
173
|
-
# ?filter[status]=published (eq)
|
|
174
|
-
# ?filter[status][neq]=draft (not equals)
|
|
175
|
-
# ?filter[views][gte]=100 (greater than or equal)
|
|
176
|
-
# ?filter[views][lte]=1000 (less than or equal)
|
|
177
|
-
# ?filter[category_id][in]=1,2,3 (in array)
|
|
178
|
-
# ?filter[status][nin]=draft,archived (not in array)
|
|
179
176
|
```
|
|
180
177
|
|
|
178
|
+
Supported operators:
|
|
179
|
+
- `?filter[field]=value` → Equals (eq)
|
|
180
|
+
- `?filter[field][neq]=value` → Not equals (neq)
|
|
181
|
+
- `?filter[field][gt]=value` → Greater than (gt)
|
|
182
|
+
- `?filter[field][gte]=value` → Greater than or equal (gte)
|
|
183
|
+
- `?filter[field][lt]=value` → Less than (lt)
|
|
184
|
+
- `?filter[field][lte]=value` → Less than or equal (lte)
|
|
185
|
+
- `?filter[field][in]=1,2,3` → In array (in)
|
|
186
|
+
- `?filter[field][nin]=1,2,3` → Not in array (nin)
|
|
187
|
+
|
|
181
188
|
## CUSTOMIZATION
|
|
182
189
|
|
|
183
190
|
### Override Collection (Scope Data)
|
|
@@ -192,8 +199,6 @@ end
|
|
|
192
199
|
### Lifecycle Hooks
|
|
193
200
|
```ruby
|
|
194
201
|
class Api::PostsController < RailsCurdBase::CurdController
|
|
195
|
-
before_action :authenticate_user!
|
|
196
|
-
|
|
197
202
|
def before_create(resource)
|
|
198
203
|
resource.author = current_user
|
|
199
204
|
resource.published_at = Time.current if resource.status == 'published'
|
|
@@ -247,7 +252,7 @@ class Api::PostsController < RailsCurdBase::CurdController
|
|
|
247
252
|
end
|
|
248
253
|
|
|
249
254
|
def set_post
|
|
250
|
-
@post = current_user.posts.
|
|
255
|
+
@post = current_user.posts.find_by(id: params[:id])
|
|
251
256
|
end
|
|
252
257
|
end
|
|
253
258
|
```
|
|
@@ -293,17 +298,9 @@ def not_found
|
|
|
293
298
|
end
|
|
294
299
|
```
|
|
295
300
|
|
|
296
|
-
### Soft Deletes
|
|
297
|
-
```ruby
|
|
298
|
-
def destroy
|
|
299
|
-
resource.update!(deleted_at: Time.current)
|
|
300
|
-
ok message: 'Deleted successfully', code: 204
|
|
301
|
-
end
|
|
302
|
-
```
|
|
303
|
-
|
|
304
301
|
## TESTING
|
|
305
302
|
|
|
306
|
-
Run
|
|
303
|
+
Run dummy application:
|
|
307
304
|
```bash
|
|
308
305
|
cd test/dummy
|
|
309
306
|
bin/rails db:migrate
|
|
@@ -320,9 +317,9 @@ curl -X POST http://localhost:3000/api/posts -H 'Content-Type: application/json'
|
|
|
320
317
|
|
|
321
318
|
## DEPENDENCIES
|
|
322
319
|
|
|
323
|
-
- rails >= 6.0
|
|
324
|
-
- kaminari >= 0.16
|
|
325
|
-
- rails_warp >= 0.1.0
|
|
320
|
+
- **rails** >= 6.0
|
|
321
|
+
- **kaminari** >= 0.16 - Pagination functionality
|
|
322
|
+
- **rails_warp** >= 0.1.0 - Unified response format
|
|
326
323
|
|
|
327
324
|
## IMPORTANT NOTES FOR AI ASSISTANTS
|
|
328
325
|
|
|
@@ -332,18 +329,20 @@ curl -X POST http://localhost:3000/api/posts -H 'Content-Type: application/json'
|
|
|
332
329
|
4. Resource is auto-derived: controller_name.singularize.classify.constantize
|
|
333
330
|
5. Override collection() to scope data (current_user.posts, etc.)
|
|
334
331
|
6. Use hooks (before_create, after_create, etc.) for callbacks
|
|
335
|
-
7. Parameters via resource_params() method (
|
|
332
|
+
7. Parameters via resource_params() method (automatically handles strong parameters)
|
|
336
333
|
8. Query parameters: page, size, sort, q, filter[field]
|
|
337
334
|
9. All query features are optional (enable/disable in supports_query)
|
|
338
335
|
10. Filter operators: eq (default), neq, gt, gte, lt, lte, in, nin
|
|
336
|
+
11. Success responses use default "success" message from RailsWarp
|
|
337
|
+
12. Error responses keep custom messages (validation failed, record not found)
|
|
338
|
+
13. Request format: supports both flat {"title":"..."} and nested {"post":{"title":"..."}} formats
|
|
339
339
|
|
|
340
340
|
## PERFORMANCE TIPS
|
|
341
341
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
- Optimize collection() for complex queries
|
|
342
|
+
1. For large datasets, ensure database fields are indexed (especially on filtered/sorted fields)
|
|
343
|
+
2. Use select() to limit queried fields (by overriding serialize_resource)
|
|
344
|
+
3. Consider caching (in hook methods)
|
|
345
|
+
4. For complex queries, override collection() method to optimize SQL
|
|
347
346
|
|
|
348
347
|
## FILE STRUCTURE
|
|
349
348
|
|
|
@@ -356,7 +355,7 @@ app/controllers/concerns/rails_curd_base/
|
|
|
356
355
|
queryable.rb # Query functionality
|
|
357
356
|
```
|
|
358
357
|
|
|
359
|
-
##
|
|
358
|
+
## CONTRIBUTING
|
|
360
359
|
|
|
361
360
|
Contributions welcome! Please:
|
|
362
361
|
- Follow existing code style
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_curd_base
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- aric.zheng
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|