og_pilot_ruby 0.1.2 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9dd502b31b2e2a9128c20c39cd1a42c78e265591084e4ad372fa9155077d2b5f
4
- data.tar.gz: 2a22d99307f56fa8e3e069c2b04b6692f44e845d7fee146f0aa5ab416cfb0e46
3
+ metadata.gz: 5a03463da25a6c59b2ee3813ae94141cf23e49949268711c211fc68da2b4c1ed
4
+ data.tar.gz: f126ee78f60803700f0c751c2098c50a3e992a88f15d9616f32c1dfb17b9477d
5
5
  SHA512:
6
- metadata.gz: 9125aaf624243e7ff5ac70a9170e2a0c5e0cd676c756cb3aeae0f793be57e1f44f120d7d9b05b0e60514d074e452475e2f443f0a7944d49f19cfab2150bd0a38
7
- data.tar.gz: b8486e526ff135fd80023a35f9b4ab9a44c446198303a8e70d227a4babee40b108c2a589136ba3871e185f76c0730f7ca240341a9837d285ae9ab18d4ea4f665
6
+ metadata.gz: e1c29c159b7e3ae1cc9556f9444cada0af6b42e5b27a520b386da978eae1b7666a7ccd0dd50bbe1bd0c9e03d7f34d52387c7ea7f957e10c8927d3aa9f58cc7e3
7
+ data.tar.gz: 7e4efd68d6b7c56294e064fc0e2b73d9acd9911f66db8805886e427469f08c2823f35524c16d091ad3cd36ebc8630ef9ef445a6a90adc85332e9c1e7fdfa43a2
data/README.md CHANGED
@@ -57,6 +57,78 @@ image_url = OgPilotRuby.create_image(
57
57
  If you omit `iat`, OG Pilot will cache the image indefinitely. Provide an `iat` to
58
58
  refresh the cache daily.
59
59
 
60
+ ## Parameters
61
+
62
+ All parameters are embedded in the signed JWT payload; the only query param is `token`.
63
+ The gem handles `iss` (domain) and `sub` (API key prefix) automatically.
64
+
65
+ ### Core parameters
66
+
67
+ | Parameter | Required | Default | Description |
68
+ |---------------|----------|----------|---------------------------------------------------------------|
69
+ | `template` | No | `"page"` | Template name |
70
+ | `title` | Yes | — | Primary title text |
71
+ | `description` | No | — | Subtitle or supporting text |
72
+ | `logo_url` | No | — | Logo image URL |
73
+ | `image_url` | No | — | Hero image URL |
74
+ | `bg_color` | No | — | Background color (hex format) |
75
+ | `text_color` | No | — | Text color (hex format) |
76
+ | `iat` | No | — | Issued-at timestamp for daily cache busting |
77
+ | `path` | No | auto-set | Request path for image rendering context. When provided, it overrides auto-resolution (see [Path handling](#path-handling)) |
78
+
79
+ ### Ruby options
80
+
81
+ | Option | Default | Description |
82
+ |-----------|---------|--------------------------------------------------------------------------|
83
+ | `json` | `false` | When `true`, sends `Accept: application/json` and parses the JSON response |
84
+ | `headers` | — | Additional HTTP headers to include with the request |
85
+ | `default` | `false` | Forces `path` to `/` when `true`, unless a manual `path` is provided (see [Path handling](#path-handling)) |
86
+
87
+ ### Template-specific parameters
88
+
89
+ | Template | Parameters |
90
+ |-------------|------------------------------------------------------------------------------------|
91
+ | `page` | `title`, `description` |
92
+ | `blog_post` | `title`, `author_name`, `author_avatar_url`, `publish_date` (ISO 8601) |
93
+ | `podcast` | `title`, `episode_date` (ISO 8601) |
94
+ | `product` | `title`, `unique_selling_point` |
95
+ | `event` | `title`, `event_date`, `event_location` |
96
+ | `book` | `title`, `description`, `book_author`, `book_series_number`, `book_description`, `book_genre` |
97
+ | `portfolio` | `title` |
98
+ | `company` | `title`, `company_logo_url`, `description` (note: `image_url` is ignored) |
99
+
100
+ ### Path handling
101
+
102
+ The `path` parameter enhances OG Pilot analytics by tracking which OG images perform better across different pages on your site. Without it, all analytics would be aggregated under the `/` path, making it difficult to understand how individual pages or content types are performing. By automatically capturing the request path, you get granular insights into click-through rates and engagement for each OG image.
103
+
104
+ The client automatically injects a `path` parameter on every request:
105
+
106
+ | Option | Behavior |
107
+ |------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
108
+ | `default: false` | Uses the current request path when available. In Rails, prefers `request.fullpath` (via the per-request store), then falls back to Rack/CGI env vars (`REQUEST_URI`, `PATH_INFO`). If no path can be determined, uses `/`. |
109
+ | `default: true` | Forces the `path` parameter to `/`, regardless of the current request (unless `path` is provided explicitly). |
110
+ | `path: "/..."` | Uses the provided path verbatim (normalized to start with `/`), overriding auto-resolution. |
111
+
112
+ **Example:**
113
+
114
+ ```ruby
115
+ image_url = OgPilotRuby.create_image(
116
+ template: "blog_post",
117
+ title: "How to Build Amazing OG Images",
118
+ default: true
119
+ )
120
+ ```
121
+
122
+ Manual override:
123
+
124
+ ```ruby
125
+ image_url = OgPilotRuby.create_image(
126
+ template: "page",
127
+ title: "Hello OG Pilot",
128
+ path: "/pricing?plan=pro"
129
+ )
130
+ ```
131
+
60
132
  Fetch JSON metadata instead:
61
133
 
62
134
  ```ruby
@@ -4,7 +4,7 @@ require "json"
4
4
  require "net/http"
5
5
  require "uri"
6
6
 
7
- require_relative "errors"
7
+ require_relative "error"
8
8
  require_relative "jwt_encoder"
9
9
 
10
10
  module OgPilotRuby
@@ -15,7 +15,14 @@ module OgPilotRuby
15
15
  @config = config
16
16
  end
17
17
 
18
- def create_image(params = {}, json: false, iat: nil, headers: {})
18
+ def create_image(params = {}, json: false, iat: nil, headers: {}, default: false)
19
+ params ||= {}
20
+ params = params.dup
21
+ # Always include a path; manual overrides win, otherwise resolve from the current request.
22
+ manual_path = params.key?(:path) ? params[:path] : params["path"]
23
+ params.delete("path") if params.key?("path")
24
+ params[:path] = manual_path.to_s.strip.empty? ? resolved_path(default:) : normalize_path(manual_path)
25
+
19
26
  uri = build_uri(params, iat:)
20
27
  response = request(uri, json:, headers:)
21
28
 
@@ -96,5 +103,79 @@ module OgPilotRuby
96
103
  def api_key_prefix
97
104
  api_key!.slice(0, 8)
98
105
  end
106
+
107
+ # Rails-first path resolution with Rack/CGI env fallback.
108
+ def resolved_path(default:)
109
+ return "/" if default
110
+
111
+ path = rails_fullpath
112
+ path = env_fullpath if path.nil? || path.empty?
113
+ normalize_path(path)
114
+ end
115
+
116
+ def rails_fullpath
117
+ return unless defined?(::Rails)
118
+
119
+ request = rails_request_from_store || rails_request_from_thread
120
+ fullpath = request.fullpath if request&.respond_to?(:fullpath)
121
+ fullpath unless fullpath.nil? || fullpath.empty?
122
+ end
123
+
124
+ def rails_request_from_store
125
+ return unless defined?(::RequestStore) && ::RequestStore.respond_to?(:store)
126
+
127
+ store = ::RequestStore.store
128
+ store[:action_dispatch_request] ||
129
+ store[:"action_dispatch.request"] ||
130
+ store[:request]
131
+ end
132
+
133
+ def rails_request_from_thread
134
+ Thread.current[:og_pilot_request] ||
135
+ Thread.current[:action_dispatch_request] ||
136
+ Thread.current[:"action_dispatch.request"] ||
137
+ Thread.current[:request]
138
+ end
139
+
140
+ def env_fullpath
141
+ request_uri = ENV["REQUEST_URI"]
142
+ return request_uri unless request_uri.nil? || request_uri.empty?
143
+
144
+ original_fullpath = ENV["ORIGINAL_FULLPATH"]
145
+ return original_fullpath unless original_fullpath.nil? || original_fullpath.empty?
146
+
147
+ path_info = ENV["PATH_INFO"]
148
+ return build_fullpath_from_path_info(path_info) unless path_info.nil? || path_info.empty?
149
+
150
+ request_path = ENV["REQUEST_PATH"]
151
+ return request_path unless request_path.nil? || request_path.empty?
152
+
153
+ nil
154
+ end
155
+
156
+ def build_fullpath_from_path_info(path_info)
157
+ query = ENV["QUERY_STRING"].to_s
158
+ return path_info if query.empty?
159
+
160
+ "#{path_info}?#{query}"
161
+ end
162
+
163
+ def normalize_path(path)
164
+ cleaned = path.to_s.strip
165
+ return "/" if cleaned.empty?
166
+
167
+ cleaned = extract_request_uri(cleaned)
168
+ cleaned = "/#{cleaned}" unless cleaned.start_with?("/")
169
+ cleaned
170
+ end
171
+
172
+ def extract_request_uri(value)
173
+ return value unless value.start_with?("http://", "https://")
174
+
175
+ uri = URI.parse(value)
176
+ uri.request_uri || "/"
177
+ rescue URI::InvalidURIError
178
+ value
179
+ end
99
180
  end
100
181
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module OgPilotRuby
4
4
  module RailsHelper
5
- def create_image(params = {}, json: false, iat: nil, headers: {}, **keyword_params)
6
- OgPilotRuby.create_image(params, json:, iat:, headers:, **keyword_params)
5
+ def create_image(params = {}, json: false, iat: nil, headers: {}, default: false, **keyword_params)
6
+ OgPilotRuby.create_image(params, json:, iat:, headers:, default:, **keyword_params)
7
7
  end
8
8
  end
9
9
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  if defined?(Rails::Railtie)
4
+ require_relative "request_store_middleware"
5
+
4
6
  module OgPilotRuby
5
7
  # Rails integration for OG Pilot Ruby
6
8
  class Railtie < Rails::Railtie
@@ -9,6 +11,10 @@ if defined?(Rails::Railtie)
9
11
  inflect.acronym 'OgPilotRuby'
10
12
  end
11
13
  end
14
+
15
+ initializer 'og_pilot_ruby.middleware' do |app|
16
+ app.middleware.use OgPilotRuby::RequestStoreMiddleware
17
+ end
12
18
  end
13
19
  end
14
20
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OgPilotRuby
4
+ # Middleware that stores the current request in Thread.current
5
+ # so OgPilotRuby::Client can access it for path resolution.
6
+ class RequestStoreMiddleware
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ request = ActionDispatch::Request.new(env)
13
+ Thread.current[:og_pilot_request] = request
14
+ @app.call(env)
15
+ ensure
16
+ Thread.current[:og_pilot_request] = nil
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OgPilotRuby
4
- VERSION = "0.1.2"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/og_pilot_ruby.rb CHANGED
@@ -25,9 +25,9 @@ module OgPilotRuby
25
25
  Client.new(config)
26
26
  end
27
27
 
28
- def create_image(params = {}, json: false, iat: nil, headers: {}, **keyword_params)
28
+ def create_image(params = {}, json: false, iat: nil, headers: {}, default: false, **keyword_params)
29
29
  params ||= {}
30
- client.create_image(params.merge(keyword_params), json:, iat:, headers:)
30
+ client.create_image(params.merge(keyword_params), json:, iat:, headers:, default:)
31
31
  end
32
32
  end
33
33
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: og_pilot_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sunergos IT LLC
@@ -72,6 +72,7 @@ files:
72
72
  - lib/og_pilot_ruby/jwt_encoder.rb
73
73
  - lib/og_pilot_ruby/rails_helper.rb
74
74
  - lib/og_pilot_ruby/railtie.rb
75
+ - lib/og_pilot_ruby/request_store_middleware.rb
75
76
  - lib/og_pilot_ruby/version.rb
76
77
  homepage: https://ogpilot.com
77
78
  licenses: