Skip to content

Commit f71a9be

Browse files
vipulnswardcoderabbitai[bot]alxgsvclaude
authored
Add CDN URL support with custom domains and subdomains (#180)
* Add support for cdn_base,use_subdomains, and custom_cname * Add missing * Apply suggestion from @coderabbitai[bot] Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Lint * fmt * More rubocop fixes * `#cdn_url` universalisation in README.md * Version bump * refactor: simplify CnameGenerator by using custom_cname directly Replace generate_cname call with direct custom_cname usage in cdn_base_postfix to reduce method indirection, addressing CodeRabbit review suggestion. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * fix: update CnameGenerator specs to match implementation Update test mocks to use custom_cname instead of generate_cname to align with the refactored implementation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * style: fix RuboCop offenses - add empty lines after module inclusion Add empty lines after module inclusion in 4 files to comply with Layout/EmptyLinesAfterModuleInclusion RuboCop rule. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * chore: upgrade to Ruby 3.4 and update CI matrix - Add Ruby 3.4 to GitHub Actions test matrix - Update style check job to use Ruby 3.4 - Add .claude/ to .gitignore and remove from git history - Fix CHANGELOG.md domain typo (ucarecdn.net -> ucarecd.net) - Add Ruby 3.4 support note to CHANGELOG - All tests pass with Ruby 3.4.5 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Alex Gusev <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent 44bc4ee commit f71a9be

File tree

18 files changed

+806
-48
lines changed

18 files changed

+806
-48
lines changed

.github/workflows/ruby.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jobs:
2020
- 3.1
2121
- 3.2
2222
- 3.3
23+
- 3.4
2324

2425
steps:
2526
- uses: actions/checkout@v3
@@ -41,7 +42,7 @@ jobs:
4142
strategy:
4243
matrix:
4344
ruby-version:
44-
- 3.3
45+
- 3.4
4546
steps:
4647
- uses: actions/checkout@v3
4748
- name: Set up Ruby

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ Gemfile.lock
1818
.ruby-version
1919
project_files
2020
*.gem
21+
.claude/

CHANGELOG.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
# Changelog
22

3+
## 4.5.0 — 2025-07-25
4+
### Added
5+
* **CDN Subdomain Support**: Added support for automatic subdomain generation to improve CDN performance and caching.
6+
* New `CnameGenerator` class for generating CNAME prefixes based on public key using SHA256 hashing
7+
* Configuration options:
8+
* `use_subdomains` - Enable automatic subdomain generation (default: `false`)
9+
* `cdn_base_postfix` - Base domain for subdomain generation (default: `https://ucarecd.net/`)
10+
* `default_cdn_base` - Original CDN base URL (default: `https://ucarecdn.com/`)
11+
* `cdn_base` - Dynamic CDN base selection based on subdomain configuration
12+
* New `cdn_url` method for `File` and `Group` entities to get CDN URLs using configured base
13+
* New `file_cdn_urls` method for `Group` entities to get CDN URLs of all files in a group without API requests
14+
* New `Uploadcare::Exception::ConfigurationError` for configuration-related errors
15+
* Ruby 3.4 support added to test matrix
16+
317
## 4.4.3 — 2024-07-06
418

519
### Added
620
* Multi page conversion parameter (`save_in_group`) added to `DocumentConverter#convert` options.
721

822
### Fixed
9-
* Fixed that signed URLs now work with ~ in the path. This also fixes signed URLs with grouped file URLs.
23+
* Fixed that signed URLs now work with ~ in the path. This also fixes signed URLs with grouped file URLs.
1024

1125
## 4.4.2 — 2024-05-29
1226

README.md

Lines changed: 84 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,28 @@
1414
Uploadcare Ruby integration handles uploads and further operations with files by
1515
wrapping Upload and REST APIs.
1616

17-
* [Installation](#installation)
18-
* [Usage](#usage)
19-
* [Uploading files](#uploading-files)
20-
* [Uploading and storing a single file](#uploading-and-storing-a-single-file)
21-
* [Multiple ways to upload files](#multiple-ways-to-upload-files)
22-
* [Uploading options](#uploading-options)
23-
* [File management](#file-management)
24-
* [File](#file)
25-
* [FileList](#filelist)
26-
* [Pagination](#pagination)
27-
* [Custom File Metadata](#custom-file-metadata)
28-
* [Group](#group)
29-
* [GroupList](#grouplist)
30-
* [Webhook](#webhook)
31-
* [Add-Ons](#add-ons)
32-
* [Project](#project)
33-
* [Conversion](#conversion)
34-
* [Useful links](#useful-links)
17+
- [Installation](#installation)
18+
- [Usage](#usage)
19+
- [Uploading files](#uploading-files)
20+
- [Uploading and storing a single file](#uploading-and-storing-a-single-file)
21+
- [Multiple ways to upload files](#multiple-ways-to-upload-files)
22+
- [Uploading options](#uploading-options)
23+
- [File management](#file-management)
24+
- [File](#file)
25+
- [FileList](#filelist)
26+
- [Pagination](#pagination)
27+
- [Custom File Metadata](#custom-file-metadata)
28+
- [Group](#group)
29+
- [GroupList](#grouplist)
30+
- [Webhook](#webhook)
31+
- [Add-Ons](#add-ons)
32+
- [Project](#project)
33+
- [Conversion](#conversion)
34+
- [Useful links](#useful-links)
3535

3636
## Requirements
37-
* ruby 3.0+
37+
38+
- ruby 3.0+
3839

3940
## Compatibility
4041

@@ -73,15 +74,18 @@ puts Uploadcare::File.info(uuid).inspect
7374
```
7475

7576
If you use `api_struct` gem in your project, replace it with `uploadcare-api_struct`:
77+
7678
```ruby
7779
gem 'uploadcare-api_struct'
7880
```
81+
7982
and run `bundle install`
8083

8184
If already not, create your project in [Uploadcare dashboard](https://app.uploadcare.com/?utm_source=github&utm_medium=referral&utm_campaign=uploadcare-ruby) and copy
8285
its [API keys](https://app.uploadcare.com/projects/-/api-keys/) from there.
8386

8487
Set your Uploadcare keys in config file or through environment variables:
88+
8589
```bash
8690
export UPLOADCARE_PUBLIC_KEY=your_public_key
8791
export UPLOADCARE_SECRET_KEY=your_private_key
@@ -109,6 +113,7 @@ You can also find an example project [here](https://github.com/uploadcare/upload
109113
In examples we’re going to use `ucarecdn.com` domain. Check your project's subdomain in the [Dashboard](https://app.uploadcare.com/projects/-/settings/#delivery).
110114

111115
### Uploading files
116+
112117
#### Uploading and storing a single file
113118

114119
Using Uploadcare is simple, and here are the basics of handling files.
@@ -124,9 +129,18 @@ Using Uploadcare is simple, and here are the basics of handling files.
124129
# URL for the file, can be used with your website or app right away
125130
@uc_file.original_file_url
126131
# => "https://ucarecdn.com/dc99200d-9bd6-4b43-bfa9-aa7bfaefca40/your-file.png"
132+
133+
# CDN URL for the file
134+
@uc_file.cdn_url
135+
# => "https://ucarecdn.com/dc99200d-9bd6-4b43-bfa9-aa7bfaefca40/"
136+
#
137+
# With subdomains enabled:
138+
# Uploadcare.config.use_subdomains = true
139+
# => "https://a1b2c3d4e5.ucarecdn.net/dc99200d-9bd6-4b43-bfa9-aa7bfaefca40/"
127140
```
128141

129142
The `store` option can have these possible values:
143+
130144
- `true`: mark the uploaded file as stored.
131145
- `false`: do not mark the uploaded file as stored and remove it after 24 hours.
132146
- `"auto"`: defers the choice of storage behavior to the [auto-store setting](https://app.uploadcare.com/projects/-/settings/#storage) for your Uploadcare project. This is the default behavior.
@@ -162,6 +176,7 @@ Uploadcare::Uploader.upload_files(files, store: 'auto')
162176

163177
Uploadcare::Uploader.upload_from_url("https://placekitten.com/96/139", store: "auto")
164178
```
179+
165180
It is possible to track progress of the upload-from-URL process. To do that, you should specify the `async` option and get a token:
166181

167182
```ruby
@@ -194,14 +209,18 @@ Uploadcare::Uploader.multipart_upload(file, store: true) do |options|
194209
puts "PROGRESS = #{progress}"
195210
end
196211
```
212+
197213
Output of the code above looks like:
214+
198215
```console
199216
PROGRESS = 4.545454545454546
200217
PROGRESS = 9.090909090909092
201218
PROGRESS = 13.636363636363637
202219
...
203220
```
221+
204222
Options available in a block:
223+
205224
- **:chunk_size** - size of each chunk in bytes;
206225
- **:object** - file object which is going to be uploaded;
207226
- **:offset** - offset from the beginning of a File object in bytes;
@@ -432,13 +451,15 @@ options = {
432451
```
433452

434453
To simply get all associated objects:
454+
435455
```ruby
436456
@list.all # => returns Array of Files
437457
```
438458

439459
#### Pagination
440460

441461
Initially, `FileList` is a paginated collection. It can be navigated using following methods:
462+
442463
```ruby
443464
@file_list = Uploadcare::FileList.file_list
444465
# Let's assume there are 250 files in cloud. By default, UC loads 100 files. To get next 100 files, do:
@@ -448,6 +469,7 @@ Initially, `FileList` is a paginated collection. It can be navigated using follo
448469
```
449470

450471
Alternatively, it's possible to iterate through full list of groups or files with `each`:
472+
451473
```ruby
452474
@list.each do |file|
453475
p file.url
@@ -495,9 +517,20 @@ Uploadcare::Group.rest_info(group.id)
495517
# group can be deleted by group ID.
496518
Uploadcare::Group.delete(group.id)
497519
# Note: This operation only removes the group object itself. All the files that were part of the group are left as is.
520+
521+
# Returns group's CDN URL
522+
@group.cdn_url
523+
# => "https://ucarecdn.com/group-id~2/"
524+
# With subdomains: "https://a1b2c3d4e5.ucarecdn.net/group-id~2/"
525+
526+
# Returns CDN URLs of all files from group without API requesting
527+
@group.file_cdn_urls
528+
# => 'https://ucarecdn.com/0513dda0-582f-447d-846f-096e5df9e2bb~2/nth/0/'
529+
# # With subdomains: 'https://a1b2c3d4e5.ucarecdn.net/0513dda0-582f-447d-846f-096e5df9e2bb~2/nth/0/'
498530
```
499531

500532
#### GroupList
533+
501534
`GroupList` is a list of `Group`
502535

503536
```ruby
@@ -509,6 +542,7 @@ Uploadcare::Group.delete(group.id)
509542
This is a paginated list, so [pagination](#Pagination) methods apply
510543

511544
#### Webhook
545+
512546
https://uploadcare.com/docs/api_reference/rest/webhooks/
513547

514548
You can use webhooks to provide notifications about your uploads to target urls.
@@ -665,6 +699,7 @@ Uploadcare::VideoConverter.convert(
665699
store: false
666700
)
667701
```
702+
668703
This method accepts options to set properties of an output file:
669704

670705
- **uuid** — the file UUID-identifier.
@@ -702,7 +737,9 @@ This method accepts options to set properties of an output file:
702737
:problems=>{}
703738
}
704739
```
740+
705741
Params in the response:
742+
706743
- **result** - info related to your transformed output(-s):
707744
- **original_source** - built path for a particular video with all the conversion operations and parameters.
708745
- **token** - a processing job token that can be used to get a [job status](https://uploadcare.com/docs/transformations/video-encoding/#status) (see below).
@@ -721,13 +758,13 @@ Uploadcare::VideoConverter.convert(
721758
)
722759
```
723760

724-
725761
To check a status of a video processing job you can simply use appropriate method of `Uploadcare::VideoConverter`:
726762

727763
```ruby
728764
token = 911933811
729765
Uploadcare::VideoConverter.status(token)
730766
```
767+
731768
`token` here is a processing job token, obtained in a response of a convert video request.
732769

733770
```ruby
@@ -743,12 +780,13 @@ Uploadcare::VideoConverter.status(token)
743780
```
744781

745782
Params in the response:
783+
746784
- **status** - processing job status, can have one of the following values:
747-
- *pending* — video file is being prepared for conversion.
748-
- *processing* — video file processing is in progress.
749-
- *finished* — the processing is finished.
750-
- *failed* — we failed to process the video, see error for details.
751-
- *canceled* — video processing was canceled.
785+
- _pending_ — video file is being prepared for conversion.
786+
- _processing_ — video file processing is in progress.
787+
- _finished_ — the processing is finished.
788+
- _failed_ — we failed to process the video, see error for details.
789+
- _canceled_ — video processing was canceled.
752790
- **error** - holds a processing error if we failed to handle your video.
753791
- **result** - repeats the contents of your processing output.
754792
- **thumbnails_group_uuid** - holds :uuid-thumb-group, a UUID of a file group with thumbnails for an output video, based on the thumbs operation parameters.
@@ -761,6 +799,7 @@ More examples and options can be found [here](https://uploadcare.com/docs/transf
761799
After each document file upload you obtain a file identifier in UUID format.
762800

763801
You can use file identifier to determine the document format and possible conversion formats.
802+
764803
```ruby
765804
Uploadcare::DocumentConverter.info("dc99200d-9bd6-4b43-bfa9-aa7bfaefca40")
766805

@@ -786,7 +825,9 @@ Uploadcare::DocumentConverter.convert(
786825
store: false
787826
)
788827
```
828+
789829
or create an image of a particular page (if using image format):
830+
790831
```ruby
791832
Uploadcare::DocumentConverter.convert(
792833
[
@@ -819,7 +860,9 @@ This method accepts options to set properties of an output file:
819860
:problems=>{}
820861
}
821862
```
863+
822864
Params in the response:
865+
823866
- **result** - info related to your transformed output(-s):
824867
- **original_source** - source file identifier including a target format, if present.
825868
- **token** - a processing job token that can be used to get a [job status](https://uploadcare.com/docs/transformations/document-conversion/#status) (see below).
@@ -843,6 +886,7 @@ To check a status of a document processing job you can simply use appropriate me
843886
token = 21120220
844887
Uploadcare::DocumentConverter.status(token)
845888
```
889+
846890
`token` here is a processing job token, obtained in a response of a convert document request.
847891

848892
```ruby
@@ -857,12 +901,13 @@ Uploadcare::DocumentConverter.status(token)
857901
```
858902

859903
Params in the response:
904+
860905
- **status** - processing job status, can have one of the following values:
861-
- *pending* — document file is being prepared for conversion.
862-
- *processing* — document file processing is in progress.
863-
- *finished* — the processing is finished.
864-
- *failed* — we failed to process the document, see error for details.
865-
- *canceled* — document processing was canceled.
906+
- _pending_ — document file is being prepared for conversion.
907+
- _processing_ — document file processing is in progress.
908+
- _finished_ — the processing is finished.
909+
- _failed_ — we failed to process the document, see error for details.
910+
- _canceled_ — document processing was canceled.
866911
- **error** - holds a processing error if we failed to handle your document.
867912
- **result** - repeats the contents of your processing output.
868913
- **uuid** - a UUID of your processed document file.
@@ -897,13 +942,14 @@ generator.generate_url("a7d5645e-5cd7-4046-819f-a6a2933bafe3")
897942
# This generates a URL that expires in 10 seconds
898943
# https://example.com/a7d5645e-5cd7-4046-819f-a6a2933bafe3/?token=exp=1714233277~acl=/a7d5645e-5cd7-4046-819f-a6a2933bafe3/~hmac=f25343104aeced3004d2cc4d49807d8d7c732300b54b154c319da5283a871a71
899944
```
945+
900946
## Useful links
901947

902-
* [Development](https://github.com/uploadcare/uploadcare-ruby/blob/main/DEVELOPMENT.md)
903-
* [Uploadcare documentation](https://uploadcare.com/docs/?utm_source=github&utm_medium=referral&utm_campaign=uploadcare-ruby)
904-
* [Upload API reference](https://uploadcare.com/api-refs/upload-api/?utm_source=github&utm_medium=referral&utm_campaign=uploadcare-ruby)
905-
* [REST API reference](https://uploadcare.com/api-refs/rest-api/?utm_source=github&utm_medium=referral&utm_campaign=uploadcare-ruby)
906-
* [Changelog](./CHANGELOG.md)
907-
* [Contributing guide](https://github.com/uploadcare/.github/blob/master/CONTRIBUTING.md)
908-
* [Security policy](https://github.com/uploadcare/uploadcare-ruby/security/policy)
909-
* [Support](https://github.com/uploadcare/.github/blob/master/SUPPORT.md)
948+
- [Development](https://github.com/uploadcare/uploadcare-ruby/blob/main/DEVELOPMENT.md)
949+
- [Uploadcare documentation](https://uploadcare.com/docs/?utm_source=github&utm_medium=referral&utm_campaign=uploadcare-ruby)
950+
- [Upload API reference](https://uploadcare.com/api-refs/upload-api/?utm_source=github&utm_medium=referral&utm_campaign=uploadcare-ruby)
951+
- [REST API reference](https://uploadcare.com/api-refs/rest-api/?utm_source=github&utm_medium=referral&utm_campaign=uploadcare-ruby)
952+
- [Changelog](./CHANGELOG.md)
953+
- [Contributing guide](https://github.com/uploadcare/.github/blob/master/CONTRIBUTING.md)
954+
- [Security policy](https://github.com/uploadcare/uploadcare-ruby/security/policy)
955+
- [Support](https://github.com/uploadcare/.github/blob/master/SUPPORT.md)

lib/uploadcare.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
require 'exception/request_error'
99
require 'exception/retry_error'
1010
require 'exception/auth_error'
11+
require 'exception/configuration_error'
1112

1213
# Entities
1314
require 'entity/entity'
@@ -29,6 +30,9 @@
2930
require 'signed_url_generators/akamai_generator'
3031
require 'signed_url_generators/base_generator'
3132

33+
# CNAME generator
34+
require 'cname_generator'
35+
3236
# Ruby wrapper for Uploadcare API
3337
#
3438
# @see https://uploadcare.com/docs/api_reference
@@ -51,4 +55,16 @@ module Uploadcare
5155
setting :framework_data, default: ''
5256
setting :file_chunk_size, default: 100
5357
setting :logger, default: Logger.new($stdout)
58+
setting :default_cdn_base, default: ENV.fetch('UPLOADCARE_DEFAULT_CDN_BASE', 'https://ucarecdn.com/')
59+
setting :cdn_base_postfix, default: ENV.fetch('UPLOADCARE_CDN_BASE', 'https://ucarecd.net/')
60+
# Enable automatic *.ucarecdn.net subdomains and CNAME generation
61+
setting :use_subdomains, default: false
62+
setting :custom_cname, default: -> { CnameGenerator.generate_cname } # CNAME domain
63+
setting :cdn_base, default: lambda {
64+
if config.use_subdomains && config.public_key
65+
CnameGenerator.cdn_base_postfix
66+
else
67+
config.default_cdn_base
68+
end
69+
}
5470
end

0 commit comments

Comments
 (0)