awesome_jsonb_translate 0.1.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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +292 -0
- data/lib/awesome_jsonb_translate/active_record.rb +179 -0
- data/lib/awesome_jsonb_translate/version.rb +5 -0
- data/lib/awesome_jsonb_translate.rb +9 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ffa6732fc05182186a76341a8c1335d428c1b74686109eefba62e64aae6723f4
|
4
|
+
data.tar.gz: 5c723ede13d6091434835a1c341804cff94f38e4cb855a6e996d2c9f61b66d49
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 21b0933074aa9548332a4ba764fbf26a7223c4e9003a38298c75a12c31d7a40fda0c2ea0719e7a3ed4352ac56a28a42d47540e2afa247447d0937595fe80f156
|
7
|
+
data.tar.gz: 9ca4739aa48e62e8e0c7ef7181bdba9c93da8bf73861aaec1f119a1c65adadc0f601bac20ef7d2b393e89f127e9472ea2151e58c5480ee74254b6c64e63087a1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 firedev.com
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
# Awesome JSONB Translate
|
2
|
+
|
3
|
+
This gem uses PostgreSQL's JSONB datatype and ActiveRecord models to translate model data.
|
4
|
+
|
5
|
+
- No extra columns or tables needed to operate
|
6
|
+
- Clean naming in the database model
|
7
|
+
- Everything is well tested
|
8
|
+
- Uses modern JSONB type for better performance and flexibility
|
9
|
+
- Falls back to default locale
|
10
|
+
|
11
|
+
## Features
|
12
|
+
|
13
|
+
- [x] `v0.1.0` It works
|
14
|
+
|
15
|
+
## Requirements
|
16
|
+
|
17
|
+
- I18n
|
18
|
+
- PostgreSQL with JSONB support (9.4+)
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem 'awesome_jsonb_translate'
|
26
|
+
```
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle
|
31
|
+
|
32
|
+
Or install it yourself as:
|
33
|
+
|
34
|
+
$ gem install awesome_jsonb_translate
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
Include `AwesomeJsonbTranslate` in your model class.
|
39
|
+
|
40
|
+
Use `translates` in your models, to define the attributes, which should be translateable:
|
41
|
+
|
42
|
+
|
43
|
+
```rb
|
44
|
+
class Model < ApplicationRecord
|
45
|
+
include AwesomeJsonbTranslate
|
46
|
+
translates :title, :description
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
---
|
51
|
+
|
52
|
+
## Examples of Supported Usage
|
53
|
+
|
54
|
+
### Assigning and Retrieving Translations
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
p = Page.new(title_en: 'English title', title_de: 'Deutscher Titel')
|
58
|
+
p = Page.new(title: { en: 'English title', de: 'Deutscher Titel'})
|
59
|
+
p.title_en # => 'English title'
|
60
|
+
p.title_de # => 'Deutscher Titel'
|
61
|
+
|
62
|
+
I18n.with_locale(:en) { p.title } # => 'English title'
|
63
|
+
I18n.with_locale(:de) { p.title } # => 'Deutscher Titel'
|
64
|
+
```
|
65
|
+
|
66
|
+
### Fallbacks
|
67
|
+
|
68
|
+
It always falls back to default locale
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
# Behavior with fallbacks enabled
|
72
|
+
p = Page.new(title_en: 'English title')
|
73
|
+
I18n.with_locale(:de) { p.title } # => 'English title' (falls back to English)
|
74
|
+
|
75
|
+
# Behavior with empty string
|
76
|
+
p = Page.new(title_en: 'English title', title_de: '')
|
77
|
+
I18n.with_locale(:de) { p.title } # => 'English title' (falls back since German is empty)
|
78
|
+
```
|
79
|
+
|
80
|
+
### Assigning a Hash Directly
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
p = Page.new(title: { en: 'English title', de: 'Deutscher Titel' })
|
84
|
+
p.title_raw # => { 'en' => 'English title', 'de' => 'Deutscher Titel' }
|
85
|
+
```
|
86
|
+
|
87
|
+
### Locale Accessors
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
p.title_en = 'Updated English title'
|
91
|
+
p.title_de = 'Aktualisierter Deutscher Titel'
|
92
|
+
```
|
93
|
+
|
94
|
+
### Querying by Translated Value (JSONB-aware)
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
# Find records by current locale value
|
98
|
+
Page.find_by(title_en: 'English title')
|
99
|
+
|
100
|
+
# which transforms to
|
101
|
+
Page.where("title->>'en' = ?", 'English title') # queries current locale
|
102
|
+
|
103
|
+
# Use with other conditions
|
104
|
+
Page.find_by(title_en: 'English title', author: 'John')
|
105
|
+
|
106
|
+
# which transforms to
|
107
|
+
Page.where("title->>'en' = ?", 'English title').where(author: 'John')
|
108
|
+
```
|
109
|
+
|
110
|
+
### Finding or Initializing Records
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
# Find existing record by translated attribute
|
114
|
+
Page.find_or_initialize_by(title_en: 'English title')
|
115
|
+
|
116
|
+
# Initialize new record if not found
|
117
|
+
new_page = Page.find_or_initialize_by(title_en: 'New Page', slug: 'new')
|
118
|
+
new_page.persisted? # => false
|
119
|
+
|
120
|
+
# Find with combined attributes
|
121
|
+
Page.find_or_initialize_by(title_en: 'English title', slug: 'english-title')
|
122
|
+
|
123
|
+
# Find or create records
|
124
|
+
existing = Page.find_or_create_by(title_en: 'English title')
|
125
|
+
new_record = Page.find_or_create_by(title_en: 'Brand New', slug: 'brand-new') # Creates and saves the record
|
126
|
+
```
|
127
|
+
|
128
|
+
### Ordering Records
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
# Sort by translated field in current locale
|
132
|
+
Page.order("title->>'en' ASC")
|
133
|
+
```
|
134
|
+
|
135
|
+
### Other Useful Methods
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
# List translated attributes
|
139
|
+
Page.translated_attributes # => [:title, :content]
|
140
|
+
|
141
|
+
# List all accessor methods
|
142
|
+
Page.translated_accessors # => [:title_en, :title_de, :content_en, :content_de]
|
143
|
+
|
144
|
+
# Check translation presence
|
145
|
+
page.translated?(:title) # => true
|
146
|
+
page.translated?(:title, :fr) # => false
|
147
|
+
|
148
|
+
# Check translation availability
|
149
|
+
page.translation_available?(:title, :en) # => true
|
150
|
+
|
151
|
+
# Get all locales that have a translation
|
152
|
+
page.available_translations(:title) # => ["en", "de"]
|
153
|
+
|
154
|
+
# Get all available locales for the record
|
155
|
+
page.available_locales # => [:en, :de]
|
156
|
+
```
|
157
|
+
|
158
|
+
---
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
class Page < ActiveRecord::Base
|
162
|
+
include AwesomeJsonbTranslate
|
163
|
+
translates :title, :content
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
Make sure that the datatype of this columns is `jsonb`:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
class CreatePages < ActiveRecord::Migration
|
171
|
+
def change
|
172
|
+
create_table :pages do |t|
|
173
|
+
t.column :title, :jsonb
|
174
|
+
t.column :content, :jsonb
|
175
|
+
t.timestamps
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
```
|
180
|
+
|
181
|
+
Use the model attributes per locale:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
p = Page.create(title_en: "English title", title_de: "Deutscher Titel")
|
185
|
+
|
186
|
+
I18n.locale = :en
|
187
|
+
p.title # => English title
|
188
|
+
|
189
|
+
I18n.locale = :de
|
190
|
+
p.title # => Deutscher Titel
|
191
|
+
|
192
|
+
I18n.with_locale :en do
|
193
|
+
p.title # => English title
|
194
|
+
end
|
195
|
+
```
|
196
|
+
|
197
|
+
The raw data is available via the suffix `_raw`:
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
p = Page.new(title: {en: 'English title', de: 'Deutscher Titel'})
|
201
|
+
|
202
|
+
p.title_raw # => {'en' => 'English title', 'de' => 'Deutscher Titel'}
|
203
|
+
```
|
204
|
+
|
205
|
+
### Find
|
206
|
+
|
207
|
+
`awesome_jsonb_translate` created a `find_by` helper.
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
Page.create!(:title_en => 'English title', :title_de => 'Deutscher Titel')
|
211
|
+
Page.create!(:title_en => 'Another English title', :title_de => 'Noch ein Deutscher Titel')
|
212
|
+
|
213
|
+
Page.find_by(title_en: 'English title') # => Find by a specific language
|
214
|
+
```
|
215
|
+
|
216
|
+
### To Param
|
217
|
+
|
218
|
+
For generating URLs with translated slugs:
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
class Page < ActiveRecord::Base
|
222
|
+
translates :title
|
223
|
+
|
224
|
+
def to_param
|
225
|
+
# Or use parameterize for URL-friendly slugs
|
226
|
+
title_en.parameterize
|
227
|
+
end
|
228
|
+
end
|
229
|
+
```
|
230
|
+
|
231
|
+
### Limitations
|
232
|
+
|
233
|
+
`awesome_jsonb_translate` patches ActiveRecord, which create the limitation, that a with `where` chained `first_or_create` and `first_or_create!` **doesn't work** as expected.
|
234
|
+
Here is an example, which **won't** work:
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
Page.where(title_en: 'Titre français').first_or_create!
|
238
|
+
```
|
239
|
+
|
240
|
+
A workaround is:
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
Page.find_or_create_by(title_en: 'Titre français')
|
244
|
+
```
|
245
|
+
|
246
|
+
## Development
|
247
|
+
|
248
|
+
```
|
249
|
+
bundle
|
250
|
+
bin/setup
|
251
|
+
bundle exec rspec
|
252
|
+
```
|
253
|
+
|
254
|
+
## Testing
|
255
|
+
|
256
|
+
To run the tests:
|
257
|
+
|
258
|
+
1. Ensure PostgreSQL is installed and running
|
259
|
+
2. Set up the test environment:
|
260
|
+
|
261
|
+
```bash
|
262
|
+
bin/setup
|
263
|
+
```
|
264
|
+
|
265
|
+
This script will:
|
266
|
+
- Install required gem dependencies
|
267
|
+
- Create the PostgreSQL test database if it doesn't exist
|
268
|
+
|
269
|
+
3. Run the tests:
|
270
|
+
|
271
|
+
```bash
|
272
|
+
bundle exec rspec
|
273
|
+
```
|
274
|
+
|
275
|
+
You can also set custom database connection details with environment variables:
|
276
|
+
|
277
|
+
```bash
|
278
|
+
DB_NAME=custom_db_name DB_USER=your_username DB_PASSWORD=your_password bundle exec rspec
|
279
|
+
```
|
280
|
+
|
281
|
+
## Troubleshooting
|
282
|
+
|
283
|
+
If you encounter issues running tests:
|
284
|
+
|
285
|
+
1. Make sure PostgreSQL is installed and running
|
286
|
+
2. Ensure the user has permissions to create databases
|
287
|
+
3. Check that the database 'awesome_jsonb_translate_test' exists or can be created
|
288
|
+
4. Run `bin/setup` to prepare the test environment
|
289
|
+
5. For more detailed database errors, run with debug flag:
|
290
|
+
```bash
|
291
|
+
DB_DEBUG=true bundle exec rspec
|
292
|
+
```
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AwesomeJsonbTranslate
|
4
|
+
module ActiveRecord
|
5
|
+
def translates(*attrs)
|
6
|
+
include InstanceMethods
|
7
|
+
|
8
|
+
class_attribute :translated_attributes, :translated_accessors, :translation_options
|
9
|
+
self.translated_attributes = attrs.map(&:to_sym)
|
10
|
+
self.translated_accessors = translated_attributes.flat_map do |attr_name|
|
11
|
+
I18n.available_locales.map do |locale|
|
12
|
+
["#{attr_name}_#{locale}", "#{attr_name}_#{locale}="]
|
13
|
+
end
|
14
|
+
end.flatten.map(&:to_sym)
|
15
|
+
self.translation_options = {}
|
16
|
+
|
17
|
+
attrs.each do |attr_name|
|
18
|
+
define_translation_accessors(attr_name)
|
19
|
+
define_translation_writer(attr_name)
|
20
|
+
define_translation_reader(attr_name)
|
21
|
+
define_raw_accessor(attr_name)
|
22
|
+
end
|
23
|
+
|
24
|
+
extend FindByMethods
|
25
|
+
end
|
26
|
+
|
27
|
+
def define_translation_accessors(attr_name)
|
28
|
+
I18n.available_locales.each do |locale|
|
29
|
+
define_translation_reader_for_locale(attr_name, locale)
|
30
|
+
define_translation_writer_for_locale(attr_name, locale)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def define_translation_reader_for_locale(attr_name, locale)
|
35
|
+
define_method("#{attr_name}_#{locale}") do
|
36
|
+
read_translation(attr_name, locale)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def define_translation_writer_for_locale(attr_name, locale)
|
41
|
+
define_method("#{attr_name}_#{locale}=") do |value|
|
42
|
+
write_translation(attr_name, locale, value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def define_translation_reader(attr_name)
|
47
|
+
define_method(attr_name) do
|
48
|
+
read_translation(attr_name, I18n.locale)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def define_translation_writer(attr_name)
|
53
|
+
define_method("#{attr_name}=") do |value|
|
54
|
+
normalized_value = value.is_a?(Hash) ? value.stringify_keys : { I18n.locale.to_s => value }
|
55
|
+
write_attribute(attr_name, (send("#{attr_name}_raw") || {}).merge(normalized_value))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def define_raw_accessor(attr_name)
|
60
|
+
define_method("#{attr_name}_raw") do
|
61
|
+
raw_value = read_attribute(attr_name)
|
62
|
+
raw_value.is_a?(Hash) ? raw_value : {}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module InstanceMethods
|
67
|
+
def translated?(attr_name, locale = I18n.locale)
|
68
|
+
value = read_translation_without_fallback(attr_name, locale)
|
69
|
+
translation_available?(attr_name, locale) && value.present?
|
70
|
+
end
|
71
|
+
|
72
|
+
def translation_available?(attr_name, locale = I18n.locale)
|
73
|
+
self.class.translated_attributes.include?(attr_name.to_sym) &&
|
74
|
+
send("#{attr_name}_raw").key?(locale.to_s)
|
75
|
+
end
|
76
|
+
|
77
|
+
def available_translations(attr_name)
|
78
|
+
return [] unless self.class.translated_attributes.include?(attr_name.to_sym)
|
79
|
+
|
80
|
+
send("#{attr_name}_raw").keys
|
81
|
+
end
|
82
|
+
|
83
|
+
def available_locales
|
84
|
+
locales = self.class.translated_attributes.flat_map do |attr_name|
|
85
|
+
available_translations(attr_name)
|
86
|
+
end.uniq
|
87
|
+
locales.map(&:to_sym)
|
88
|
+
end
|
89
|
+
|
90
|
+
def read_translation(attr_name, locale)
|
91
|
+
translations = send("#{attr_name}_raw")
|
92
|
+
value = translations[locale.to_s]
|
93
|
+
|
94
|
+
if value.blank? && locale != I18n.default_locale
|
95
|
+
translations[I18n.default_locale.to_s]
|
96
|
+
else
|
97
|
+
value
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def read_translation_without_fallback(attr_name, locale)
|
102
|
+
translations = send("#{attr_name}_raw")
|
103
|
+
translations[locale.to_s]
|
104
|
+
end
|
105
|
+
|
106
|
+
def write_translation(attr_name, locale, value)
|
107
|
+
translations = send("#{attr_name}_raw").dup
|
108
|
+
translations[locale.to_s] = value
|
109
|
+
write_attribute(attr_name, translations)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
module FindByMethods
|
114
|
+
# Override find_by to handle translated attributes
|
115
|
+
def find_by(attributes)
|
116
|
+
# Check if any of the keys represent translated attributes
|
117
|
+
has_translated_attrs = attributes.keys.any? do |key|
|
118
|
+
translated_accessors.include?(key.to_sym)
|
119
|
+
end
|
120
|
+
|
121
|
+
# If no translated attributes, use default implementation
|
122
|
+
return super unless has_translated_attrs
|
123
|
+
|
124
|
+
translated_attrs = {}
|
125
|
+
regular_attrs = {}
|
126
|
+
|
127
|
+
attributes.each do |key, value|
|
128
|
+
key_s = key.to_s
|
129
|
+
if key_s.include?('_') && !key_s.end_with?('=')
|
130
|
+
parts = key_s.split('_')
|
131
|
+
locale = parts.last
|
132
|
+
attr_name = parts[0..-2].join('_')
|
133
|
+
|
134
|
+
if translated_attributes.include?(attr_name.to_sym)
|
135
|
+
translated_attrs[attr_name] ||= {}
|
136
|
+
translated_attrs[attr_name][locale] = value
|
137
|
+
else
|
138
|
+
regular_attrs[key] = value
|
139
|
+
end
|
140
|
+
else
|
141
|
+
regular_attrs[key] = value
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
scope = where(regular_attrs)
|
146
|
+
|
147
|
+
translated_attrs.each do |attr_name, locales|
|
148
|
+
locales.each do |locale, value|
|
149
|
+
scope = scope.where("#{attr_name}->>'#{locale}' = ?", value)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
scope.first
|
154
|
+
end
|
155
|
+
|
156
|
+
# Override find_or_initialize_by to handle translated attributes
|
157
|
+
def find_or_initialize_by(attributes)
|
158
|
+
result = find_by(attributes)
|
159
|
+
return result if result
|
160
|
+
|
161
|
+
# If no record found, initialize with the given attributes
|
162
|
+
new_record = new
|
163
|
+
new_record.assign_attributes(attributes)
|
164
|
+
new_record
|
165
|
+
end
|
166
|
+
|
167
|
+
# Override find_or_create_by to handle translated attributes
|
168
|
+
def find_or_create_by(attributes)
|
169
|
+
result = find_by(attributes)
|
170
|
+
return result if result
|
171
|
+
|
172
|
+
# If no record found, create with the given attributes
|
173
|
+
create(attributes)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
ActiveRecord::Base.extend AwesomeJsonbTranslate::ActiveRecord
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: awesome_jsonb_translate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Your Name
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-04-18 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: activerecord
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '5.0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '5.0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: i18n
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0.7'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.7'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: pg
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.0'
|
47
|
+
type: :development
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: rake
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '13.0'
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '13.0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: rspec
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.0'
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '3.0'
|
82
|
+
description: This gem uses PostgreSQL's JSONB datatype to store and retrieve translations
|
83
|
+
for ActiveRecord models without extra columns or tables
|
84
|
+
email:
|
85
|
+
- your.email@example.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- LICENSE.txt
|
91
|
+
- README.md
|
92
|
+
- lib/awesome_jsonb_translate.rb
|
93
|
+
- lib/awesome_jsonb_translate/active_record.rb
|
94
|
+
- lib/awesome_jsonb_translate/version.rb
|
95
|
+
homepage: https://github.com/username/awesome_jsonb_translate
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata:
|
99
|
+
homepage_uri: https://github.com/username/awesome_jsonb_translate
|
100
|
+
source_code_uri: https://github.com/username/awesome_jsonb_translate/tree/master
|
101
|
+
documentation_uri: https://github.com/username/awesome_jsonb_translate/blob/master/README.md
|
102
|
+
changelog_uri: https://github.com/username/awesome_jsonb_translate/blob/master/CHANGELOG.md
|
103
|
+
rubygems_mfa_required: 'true'
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 2.6.0
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubygems_version: 3.6.2
|
119
|
+
specification_version: 4
|
120
|
+
summary: ActiveRecord translations using PostgreSQL's JSONB data type
|
121
|
+
test_files: []
|