bullet_train 1.2.10 → 1.2.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/account/two_factors_controller.rb +21 -5
- data/app/helpers/account/forms_helper.rb +3 -1
- data/app/javascript/controllers/clipboard_controller.js +1 -1
- data/app/javascript/controllers/connection_workflow_controller.js +7 -0
- data/app/javascript/controllers/desktop_menu_controller.js +26 -0
- data/app/javascript/controllers/index.js +4 -0
- data/app/javascript/index.js +2 -1
- data/app/javascript/support/turn.js +183 -0
- data/app/models/concerns/users/base.rb +1 -1
- data/app/views/account/invitations/_form.html.erb +2 -2
- data/app/views/account/memberships/_form.html.erb +2 -2
- data/app/views/account/memberships/_membership.html.erb +1 -1
- data/app/views/account/teams/_breadcrumbs.html.erb +12 -5
- data/app/views/account/teams/_team.html.erb +3 -23
- data/app/views/account/two_factors/verify.js.erb +1 -0
- data/app/views/devise/registrations/_two_factor.html.erb +29 -8
- data/app/views/devise/sessions/new.html.erb +4 -2
- data/app/views/layouts/docs.html.erb +7 -7
- data/app/views/showcase/engine/_stylesheets.html.erb +1 -0
- data/config/locales/en/teams.en.yml +2 -0
- data/config/locales/en/users.en.yml +8 -1
- data/config/routes.rb +5 -1
- data/docs/action-models.md +5 -5
- data/docs/api/versioning.md +0 -2
- data/docs/api.md +4 -4
- data/docs/application-options.md +1 -1
- data/docs/billing/usage.md +94 -16
- data/docs/field-partials.md +21 -20
- data/docs/font-awesome-pro.md +1 -1
- data/docs/getting-started.md +3 -3
- data/docs/i18n.md +3 -3
- data/docs/indirection.md +6 -4
- data/docs/namespacing.md +1 -1
- data/docs/onboarding.md +8 -8
- data/docs/overriding.md +1 -1
- data/docs/permissions.md +1 -1
- data/docs/seeds.md +1 -1
- data/docs/testing.md +2 -1
- data/docs/themes.md +18 -11
- data/docs/tunneling.md +2 -2
- data/docs/upgrades.md +2 -1
- data/lib/bullet_train/engine.rb +6 -0
- data/lib/bullet_train/version.rb +1 -1
- data/lib/bullet_train.rb +2 -1
- data/lib/colorizer.rb +1 -1
- data/lib/tasks/bullet_train_tasks.rake +29 -12
- metadata +35 -9
- data/app/controllers/turbo_devise_controller.rb +0 -19
- data/app/views/account/invitations/_invitation.json.jbuilder +0 -7
- data/app/views/account/invitations/index.json.jbuilder +0 -1
- data/app/views/account/invitations/show.json.jbuilder +0 -1
- data/app/views/account/teams/_team.json.jbuilder +0 -9
- data/app/views/account/teams/index.json.jbuilder +0 -1
- data/app/views/account/teams/show.json.jbuilder +0 -1
data/docs/action-models.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
Action Models make it easy to scaffold and implement user-facing custom actions in your Bullet Train application and API in a RESTful way. Action Models are perfect for situations where you want one or more of the following:
|
4
4
|
|
5
5
|
- Bulk actions for a model where users can select one or more objects as targets.
|
6
|
-
- Long-running background tasks where you want to keep users updated on their progress in the UI or notify
|
6
|
+
- Long-running background tasks where you want to keep users updated on their progress in the UI or notify them after completion.
|
7
7
|
- Actions that have one or more configuration options available.
|
8
8
|
- Tasks that can be configured now but scheduled to take place later.
|
9
9
|
- Actions where you want to keep an in-app record of when it happened and who initiated the action.
|
@@ -44,11 +44,11 @@ end
|
|
44
44
|
|
45
45
|
### 1. Purchase Bullet Train Pro
|
46
46
|
|
47
|
-
First, [purchase Bullet Train Pro](https://buy.stripe.com/aEU7vc4dBfHtfO89AV). Once you've completed this process, you'll be issued a private token for the Bullet Train Pro package server. The process is currently completed manually, so you may have to
|
47
|
+
First, [purchase Bullet Train Pro](https://buy.stripe.com/aEU7vc4dBfHtfO89AV). Once you've completed this process, you'll be issued a private token for the Bullet Train Pro package server. The process is currently completed manually, so you may have to wait a little to receive your keys.
|
48
48
|
|
49
49
|
### 2. Install the Package
|
50
50
|
|
51
|
-
|
51
|
+
Then you can specify the Ruby gem in your `Gemfile`:
|
52
52
|
|
53
53
|
```ruby
|
54
54
|
source "https://YOUR_TOKEN_HERE@gem.fury.io/bullettrain" do
|
@@ -104,7 +104,7 @@ Because Action Models are just regular models, you can add new fields to them wi
|
|
104
104
|
For example:
|
105
105
|
|
106
106
|
```
|
107
|
-
rails g migration
|
107
|
+
rails g migration add_notify_users_to_projects_archive_actions notify_users:boolean
|
108
108
|
# side quest: update the generated migration with `default: false` on the new boolean field.
|
109
109
|
bin/super-scaffold crud-field Projects::ArchiveAction notify_users:boolean
|
110
110
|
```
|
@@ -145,4 +145,4 @@ This final type of action is available for things like importers that don't nece
|
|
145
145
|
|
146
146
|
### Do Action Models have to be persisted to the database?
|
147
147
|
|
148
|
-
No. Action Models extend from `ApplicationRecord` by default, but if you're not using features that depend on persistence to the database, you can make them `include ActiveModel::API` instead. That said, it's probably not worth the trouble. As an alternative, consider just including `Actions::CleansUp` in your action to ensure it removes itself from the database after completion.
|
148
|
+
No. Action Models extend from `ApplicationRecord` by default, but if you're not using features that depend on persistence to the database, you can make them `include ActiveModel::API` instead. That said, it's probably not worth the trouble. As an alternative, consider just including `Actions::CleansUp` in your action to ensure it removes itself from the database after completion.
|
data/docs/api/versioning.md
CHANGED
@@ -31,8 +31,6 @@ If you're in a situation where you know you need to bump your API version to hel
|
|
31
31
|
rake bullet_train:api:bump_version
|
32
32
|
```
|
33
33
|
|
34
|
-
> TODO This Rake task doesn't exist yet.
|
35
|
-
|
36
34
|
## What happens when you bump an API version?
|
37
35
|
When you bump your API version, all of the files and directories that are namespaced with the API version number will be duplicated into a new namespace for the new API version number.
|
38
36
|
|
data/docs/api.md
CHANGED
@@ -19,7 +19,7 @@ APIs are built using standard Rails tools like `ActiveController::API`, [Strong
|
|
19
19
|
In the same way we've adopted [Devise](https://github.com/heartcombo/devise) for best-of-breed and battle-tested authentication on the browser side, we've adopted [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper) for best-of-breed and battle-tested authentication on the API side.
|
20
20
|
|
21
21
|
### DRY Authorization Logic
|
22
|
-
Because our API endpoints are standard Rails controllers, they're able to leverage the exact same [permissions definitions and authorization logic](
|
22
|
+
Because our API endpoints are standard Rails controllers, they're able to leverage the exact same [permissions definitions and authorization logic](/docs/permissions) as our account controllers.
|
23
23
|
|
24
24
|
## Structure
|
25
25
|
Where vanilla Rails uses a single controller in `app/controllers` for both in-browser and API requests, Bullet Train splits these into two separate controllers, one in `app/controllers/account` and another in `app/controllers/api/v1`, although a lot of logic is shared between the two.
|
@@ -40,7 +40,7 @@ The primary definition of Strong Parameters for a given resource is defined in t
|
|
40
40
|
include strong_parameters_from_api
|
41
41
|
```
|
42
42
|
|
43
|
-
> This may feel counter-intuitive to some developers and you might wonder why we don't flip this around and have the primary definition in the account controller and have the API controller delegate to it. The answer is a pragmatic one: creating and maintaining the defintion of Strong Paramters in the API controller means it gets automatically frozen in time should you ever need to [bump your API version number](/api/
|
43
|
+
> This may feel counter-intuitive to some developers and you might wonder why we don't flip this around and have the primary definition in the account controller and have the API controller delegate to it. The answer is a pragmatic one: creating and maintaining the defintion of Strong Paramters in the API controller means it gets automatically frozen in time should you ever need to [bump your API version number](/docs/api/versioning.md). We probably _could_ accomplish this if things were the other way around, but it wouldn't happen automatically.
|
44
44
|
|
45
45
|
If by chance there are additional attributes that should be permitted or specific logic that needs to be run as part of the account controller (or inversely, only in the API controller), you can specify that in the controller like so:
|
46
46
|
|
@@ -71,7 +71,7 @@ end
|
|
71
71
|
```
|
72
72
|
|
73
73
|
## Usage Example
|
74
|
-
First, provision a platform application in section titled "Your Applications" in the "Developers" menu of the application. When you create a new platform application, an access token that doesn't automatically expire will be automatically provisioned along with it. You can then use the access token to hit the API, as seen in the following Ruby-based example:
|
74
|
+
First, provision a platform application in the section titled "Your Applications" in the "Developers" menu of the application. When you create a new platform application, an access token that doesn't automatically expire will be automatically provisioned along with it. You can then use the access token to hit the API, as seen in the following Ruby-based example:
|
75
75
|
|
76
76
|
```ruby
|
77
77
|
require 'net/http'
|
@@ -103,4 +103,4 @@ response = client.patch("/api/v1/teams/1", {team: team}.to_json, headers)
|
|
103
103
|
- [API Versioning](/docs/api/versioning.md)
|
104
104
|
|
105
105
|
## A Note About Other Serializers and API Frameworks
|
106
|
-
In early versions of Bullet Train we made the decision to adopt a specific serialization library, [ActiveModelSerializers](https://github.com/rails-api/active_model_serializers) and in subsequent versions we went as far as to adopt an entire third-party framework ([Grape](https://github.com/ruby-grape/grape)) and a third-party API specification ([JSON:API](https://jsonapi.org)). We now consider it out-of-scope to try and make such decisions on behalf of developers. Support for them in Bullet Train applications and in Super Scaffolding could be created by third-parties.
|
106
|
+
In early versions of Bullet Train we made the decision to adopt a specific serialization library, [ActiveModelSerializers](https://github.com/rails-api/active_model_serializers), and in subsequent versions we went as far as to adopt an entire third-party framework ([Grape](https://github.com/ruby-grape/grape)) and a third-party API specification ([JSON:API](https://jsonapi.org)). We now consider it out-of-scope to try and make such decisions on behalf of developers. Support for them in Bullet Train applications and in Super Scaffolding could be created by third-parties.
|
data/docs/application-options.md
CHANGED
@@ -23,7 +23,7 @@ The helper methods below can also be directly invoked in your application if you
|
|
23
23
|
| STRIPE_CLIENT_ID | See [Bullet Train Billing for Stripe](/docs/billing/stripe.md) for more information and related environment variables. |
|
24
24
|
| CLOUDINARY_URL | Enables use of Cloudinary for handling images. |
|
25
25
|
| TWO_FACTOR_ENCRYPTION_KEY | Enables two-factor authentication through Devise. |
|
26
|
-
| INVITATION_KEYS | See
|
26
|
+
| INVITATION_KEYS | See [Invitation Only](/docs/authentication.md) for more information. |
|
27
27
|
| FONTAWESOME_NPM_AUTH_TOKEN | Enables use of Font Awesome. |
|
28
28
|
| SILENCE_LOGS | Silences Super Scaffolding logs. |
|
29
29
|
| TESTING_PROVISION_KEY | Creates a test `Platform::Application` by accessing `/testing/provision?key=your_provision_key` |
|
data/docs/billing/usage.md
CHANGED
@@ -45,7 +45,31 @@ Note this is different than how many Rails engines ask you to install migrations
|
|
45
45
|
rake db:migrate
|
46
46
|
```
|
47
47
|
|
48
|
-
|
48
|
+
### 2.5. Add Model Support
|
49
|
+
|
50
|
+
There are two concerns that need to be added to your application models.
|
51
|
+
|
52
|
+
The first concern is `Billing::UsageSupport` and it allows tracking of usage of verbs on the models you want to support tracking usage on. It is recommended to add this capability to all models, so you can add this.
|
53
|
+
|
54
|
+
```
|
55
|
+
# app/models/application_record.rb
|
56
|
+
|
57
|
+
class ApplicationRecord
|
58
|
+
include Billing::Usage
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
The second concern is `Billing::HasTrackers` and it allows any model to hold the usage tracking. This is usually done on the `Team` model.
|
63
|
+
|
64
|
+
```
|
65
|
+
# app/models/team.rb
|
66
|
+
|
67
|
+
class Team
|
68
|
+
include Billing::HasTrackers
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
## Configuration
|
49
73
|
Usage limit configuration piggybacks on your [product definitions](/docs/billing/stripe.md) in `config/models/billing/products.yml`. It may help to make reference to the [default product definitions in the Bullet Train starter repository](https://github.com/bullet-train-co/bullet_train/blob/main/config/models/billing/products.yml).
|
50
74
|
|
51
75
|
## Basic Usage Limits
|
@@ -63,21 +87,37 @@ basic:
|
|
63
87
|
upgradable: true
|
64
88
|
```
|
65
89
|
|
66
|
-
|
90
|
+
Any verb that your model supports can be used. It is recommended to standardize on using the action as the verb. For example, when creating a new model, use the verb _create_. When deleting a model, use the verb _delete_, and so on.
|
91
|
+
|
92
|
+
It's important to note that `have` is a special verb and represents the simple `count` of a given model on a `Team`. All _other_ verbs will be interpreted as [time-based usage limits](#time-based-usage-limits).
|
67
93
|
|
68
94
|
### Options
|
69
|
-
- `enforcement` can be `hard` or `soft`.
|
95
|
+
- `enforcement` can be `hard` or `soft`.
|
70
96
|
- When a `hard` limit is hit, the create form will be disabled.
|
71
97
|
- When a `soft` limit is hit, users are simply notified, but can continue to surpass the limit.
|
72
98
|
- `upgradable` indicates whether or not a user should be prompted to upgrade when they hit this limit.
|
73
99
|
|
74
100
|
### Excluding Records from `have` Usage Limits
|
75
|
-
All models have an overridable `billable` scope that includes all records by default. You can override this scope to ensure that certain records are filtered out from consideration when calculating usage limits. For example, we do the following on `Membership` to exclude removed team members from contributing to any limitation put on the number of team members, like so:
|
101
|
+
All models have an overridable `billable` scope that includes all records by default. You can override this scope on any given model to ensure that certain records are filtered out from consideration when calculating usage limits. For example, we do the following on `Membership` to exclude removed team members from contributing to any limitation put on the number of team members, like so:
|
76
102
|
|
77
103
|
```ruby
|
78
104
|
scope :billable, -> { current_and_invited }
|
79
105
|
```
|
80
106
|
|
107
|
+
Another example may be excluding "archived" items within the billable usage count such as:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
module Archivable
|
111
|
+
extend ActiveSupport::Concern
|
112
|
+
|
113
|
+
included do
|
114
|
+
scope :billable, -> { where(archived_at: nil) }
|
115
|
+
|
116
|
+
# ...
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
81
121
|
## Time-Based Usage Limits
|
82
122
|
|
83
123
|
### Configuring Limits
|
@@ -95,7 +135,7 @@ free:
|
|
95
135
|
```
|
96
136
|
|
97
137
|
- `count` is how many times something can happen.
|
98
|
-
- `duration` and `interval` represent the time period we'll track for, e.g. "3 days" in this case.
|
138
|
+
- `duration` and `interval` represent the time period we'll track for, e.g. "3 days" in this case.
|
99
139
|
- Valid options for `interval` are anything you can append to an integer, e.g. `minutes`, `hours`, `days`, `weeks`, `months`, etc., both plural and singular.
|
100
140
|
|
101
141
|
### Tracking Usage
|
@@ -112,7 +152,7 @@ class Blogs::Post < ApplicationRecord
|
|
112
152
|
end
|
113
153
|
```
|
114
154
|
|
115
|
-
If you'd like to increment the usage count by more than one, you can pass a quantity like `count: 5` to this call.
|
155
|
+
It is important that you use the past tense of the verb when tracking so it is tracked appropriately. If you'd like to increment the usage count by more than one, you can pass a quantity like `count: 5` to this call.
|
116
156
|
|
117
157
|
### Cycling Trackers Regularly
|
118
158
|
We include a Rake task you'll need to run on a regular basis in order to cycle the usage trackers that are created at a `Team` level. By default, you should probably run this every five minutes:
|
@@ -123,26 +163,64 @@ rake billing:cycle_usage_trackers
|
|
123
163
|
|
124
164
|
## Checking Usage Limits
|
125
165
|
|
166
|
+
### Checking Time-Based Limits
|
167
|
+
To make decisions based on or enforce time-based `hard` limits in your views and controllers, you can use the `current_limits` helper like this:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
current_limits.can?(:publish, Blogs::Post)
|
171
|
+
```
|
172
|
+
|
173
|
+
(You can also pass quantities like `count: 5` as an option.)
|
174
|
+
|
126
175
|
### Checking Basic Limits
|
127
176
|
For basic `have` limits, forms generated by Super Scaffolding will be automatically disabled when a `hard` limit has been hit. Index views will also alert users to a limit being hit or broken for both `hard` and `soft` limits.
|
128
177
|
|
129
178
|
> If your Bullet Train application scaffolding predates this feature, you can reference the newest Tangible Things [index template](https://github.com/bullet-train-co/bullet_train-super_scaffolding/blob/main/app/views/account/scaffolding/completely_concrete/tangible_things/_index.html.erb) and [form template](https://github.com/bullet-train-co/bullet_train-super_scaffolding/blob/main/app/views/account/scaffolding/completely_concrete/tangible_things/_form.html.erb) to see how we're using the `shared/limits/index` and `shared/limits/form` partials to present and enforce usage limits, and copy this usage in your own views.
|
130
179
|
|
131
|
-
|
132
|
-
To make decisions based on or enforce time-based limits in your views and controllers, you can use the `current_limits` helper like this:
|
180
|
+
To make decisions in other views or within controllers, you can use the `#exhausted?` method on the `current_limits` helper to check if any basic `have` limits have been hit or exceeded.
|
133
181
|
|
134
|
-
```
|
135
|
-
|
136
|
-
|
182
|
+
```ruby
|
183
|
+
# Inspects broken hard limits by default
|
184
|
+
current_limits.exhausted?(Blogs::Post)
|
137
185
|
|
138
|
-
|
186
|
+
# Or you can specify the `enforcement` level
|
187
|
+
current_limits.exhausted?(Blogs::Post, :soft)
|
188
|
+
```
|
139
189
|
|
140
190
|
#### Presenting an Error
|
141
191
|
|
142
|
-
If you
|
192
|
+
If you want to present an error or warning to the user based on their usage, there themed alert partials that can be displayed in your views. These partials can be rendered via the path `shared/limits/error` and `shared/limits/warning` respectively.
|
143
193
|
|
194
|
+
```ruby
|
195
|
+
<%= render "shared/limits/warning", model: model.class %>
|
196
|
+
|
197
|
+
<%= render "shared/limits/error", action: :create, model: model.class, count: 1, cancel_path: cancel_path %>
|
144
198
|
```
|
145
|
-
|
146
|
-
|
199
|
+
|
200
|
+
These partials have various local assigns that are used to configure the partial.
|
201
|
+
|
202
|
+
* `action` - the `verb` to check the usage on the model for. Defaults to `have`.
|
203
|
+
* `color` - the `color` value to use for the alert partial. Defaults to `red` for errors and `yellow` for warnings.
|
204
|
+
* `count` - the number of objects intended to be acted upon. Defaults to 1.
|
205
|
+
* `model` - the `class` relationship as the model to inspect usage on. Defaults to `form.object.class`.
|
206
|
+
|
207
|
+
### Changing Products
|
208
|
+
The default list of products that the limits are based off of are the products available from your Billing products, which is most likely a list of subscription plans from Stripe.
|
209
|
+
|
210
|
+
You can change this default behavior by creating your own billing limiter and overriding the `current_products` method. This method should return a list of products that all respond to a `limits` message. The rest of the behavior is encapsulated in the `Billing::Limiter::Base` concern.
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
# app/models/billing/email_limiter.rb
|
214
|
+
|
215
|
+
class Billing::EmailLimiter
|
216
|
+
include Billing::Limiter::Base
|
217
|
+
|
218
|
+
def current_products
|
219
|
+
products = Billing::Product.data
|
220
|
+
|
221
|
+
EmailService.retrieve_product_tiers.map do |tier|
|
222
|
+
add_product_limit(tier, products)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
147
226
|
```
|
148
|
-
> TODO This technically works but needs to be redone. Too limited.
|
data/docs/field-partials.md
CHANGED
@@ -40,7 +40,7 @@ Breaking down the invocation:
|
|
40
40
|
- `text_field` matches the name of the native Rails form field helper we want to invoke.
|
41
41
|
- The `form` option passes a reference to the form object the field will exist within.
|
42
42
|
- The `method` option specifies which attribute of the model the field represents, in the same way as the first parameter of the basic Rails `text_field` helper.
|
43
|
-
- The `options` option is basically a passthrough, allowing you to specify options which will passed directly to the underlying Rails form field helper.
|
43
|
+
- The `options` option is basically a passthrough, allowing you to specify options which will be passed directly to the underlying Rails form field helper.
|
44
44
|
|
45
45
|
The 1:1 relationship between these field partials and their underlying Rails form helpers is an important design decision. For example, the way `options` is passed through to native Rails form field helpers means that experienced Rails developers will still be able to leverage what they remember about using Rails, while those of us who don't readily remember all the various options of those helpers can make use of [the standard Rails documentation](https://guides.rubyonrails.org/form_helpers.html) and the great wealth of Rails code examples available online and still take advantage of these field partials. That means the amount of documentation we need to maintain for these field partials is strictly for those features that are in addition to what Rails provides by default.
|
46
46
|
|
@@ -76,7 +76,7 @@ When you're including multiple fields, you can DRY up redundant settings (e.g. `
|
|
76
76
|
```
|
77
77
|
|
78
78
|
## Field partials that integrate with third-party service providers
|
79
|
-
- `cloudinary` makes it trivial to upload photos and images to [Cloudinary](https://cloudinary.com) and store their resulting Cloudinary ID as an attribute of the model backing the form. To enable this field partial, sign up for Cloudinary and copy the "Cloudinary URL" they provide you with into your `config/application.yml` as `CLOUDINARY_URL`. If you use our [Heroku app.json] to provision your production environment, this will happen in that environment automatically.
|
79
|
+
- `cloudinary` makes it trivial to upload photos and images to [Cloudinary](https://cloudinary.com) and store their resulting Cloudinary ID as an attribute of the model backing the form. To enable this field partial, sign up for Cloudinary and copy the "Cloudinary URL" they provide you with into your `config/application.yml` as `CLOUDINARY_URL`. If you use our [Heroku app.json](https://github.com/bullet-train-co/bullet_train/blob/main/app.json) to provision your production environment, this will happen in that environment automatically.
|
80
80
|
|
81
81
|
## Yaml Configuration
|
82
82
|
The localization Yaml file (where you configure label and option values for a field) is automatically generated when you run Super Scaffolding for a model. If you haven't done this yet, the localization Yaml file for `Scaffolding::CompletelyConcrete::TangibleThing` serves as a good example. Under `en.scaffolding/completely_concrete/tangible_things.fields` you'll see definitions like this:
|
@@ -109,23 +109,25 @@ Certain form field partials like `buttons` and `super_select` can also have thei
|
|
109
109
|
|
110
110
|
## Available Field Partials
|
111
111
|
|
112
|
-
| Field Partial
|
113
|
-
|
114
|
-
| `boolean`
|
115
|
-
| [`buttons`](/docs/field-partials/buttons.md)
|
116
|
-
| `cloudinary_image`
|
117
|
-
| `color_picker`
|
118
|
-
| `date_and_time_field`
|
119
|
-
| `date_field`
|
120
|
-
| `email_field`
|
121
|
-
|
|
122
|
-
| `
|
123
|
-
| `
|
124
|
-
| `
|
125
|
-
|
|
126
|
-
| `
|
127
|
-
| `
|
128
|
-
| `
|
112
|
+
| Field Partial | Data Type | Multiple Values? | Assignment Helpers | JavaScript Library | Description |
|
113
|
+
|--------------------------------------------------------|--------------|------------------|-------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
|
114
|
+
| `boolean` | `boolean` | | `assign_boolean` | | |
|
115
|
+
| [`buttons`](/docs/field-partials/buttons.md) | `string` | Optionally | `assign_checkboxes` | | |
|
116
|
+
| `cloudinary_image` | `string` | | | | |
|
117
|
+
| `color_picker` | | | | [pickr](https://simonwep.github.io/pickr/) | |
|
118
|
+
| `date_and_time_field` | `datetime` | | `assign_date_and_time` | [Date Range Picker](https://www.daterangepicker.com) | |
|
119
|
+
| `date_field` | `date` | | `assign_date` | [Date Range Picker](https://www.daterangepicker.com) | |
|
120
|
+
| `email_field` | `string` | | | | |
|
121
|
+
| `emoji_field` | `string` | | | [Emoji Mart](https://missiveapp.com/open/emoji-mart) | A front-end library which allows users to browse and select emojis with ease. | |
|
122
|
+
| [`file_field`](/docs/field-partials/file-field.md) | `attachment` | | | [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) | |
|
123
|
+
| `options` | `string` | Optionally | `assign_checkboxes` | | |
|
124
|
+
| `password_field` | `string` | | | | |
|
125
|
+
| `phone_field` | `string` | | | [International Telephone Input](https://intl-tel-input.com) | Ensures telephone numbers are in a format that can be used by providers like Twilio. |
|
126
|
+
| [`super_select`](/docs/field-partials/super-select.md) | `string` | Optionally | `assign_select_options` | [Select2](https://select2.org) | Provides powerful option search, AJAX search, and multi-select functionality. |
|
127
|
+
| `text_area` | `text` | | | | |
|
128
|
+
| `text_field` | `string` | | | | |
|
129
|
+
| `number_field` | `integer` | | | | |
|
130
|
+
| `trix_editor` | `text` | | | [Trix](https://github.com/basecamp/trix) | Basic HTML-powered formatting features and support for at-mentions amongst team members. |
|
129
131
|
|
130
132
|
## A Note On Data Types
|
131
133
|
Set the data type to `jsonb` whenever passing the `multiple` option to a new attribute.
|
@@ -138,4 +140,3 @@ Set the data type to `jsonb` whenever passing the `multiple` option to a new att
|
|
138
140
|
- [`buttons`](/docs/field-partials/buttons.md)
|
139
141
|
- [`super_select`](/docs/field-partials/super-select.md)
|
140
142
|
- [`file_field`](/docs/field-partials/file-field.md)
|
141
|
-
|
data/docs/font-awesome-pro.md
CHANGED
@@ -18,7 +18,7 @@ Once you buy a license for Font Awesome Pro, set `FONTAWESOME_NPM_AUTH_TOKEN` in
|
|
18
18
|
- Add `export FONTAWESOME_NPM_AUTH_TOKEN=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX` in `~/.zshrc`.
|
19
19
|
- Restart your terminal.
|
20
20
|
|
21
|
-
If you're configuring this in another type of shell, please let us know what the steps are [in a new GitHub issue](
|
21
|
+
If you're configuring this in another type of shell, please let us know what the steps are [in a new GitHub issue](https://github.com/bullet-train-co/bullet_train/issues/new) and we'll add them here for others.
|
22
22
|
|
23
23
|
### 2. Add `.npmrc` Configuration
|
24
24
|
|
data/docs/getting-started.md
CHANGED
@@ -8,7 +8,7 @@ Whether you want to build a new application with Bullet Train or contribute to B
|
|
8
8
|
|
9
9
|
If you're using Bullet Train for the first time, begin by learning these five important techniques:
|
10
10
|
|
11
|
-
1. Use `rails g model` to create and `bin/super-scaffold` to scaffold a new model:
|
11
|
+
1. Use `rails g model` to create and `bin/super-scaffold crud` to scaffold a new model:
|
12
12
|
|
13
13
|
```
|
14
14
|
rails g model Project team:references name:string
|
@@ -17,7 +17,7 @@ If you're using Bullet Train for the first time, begin by learning these five im
|
|
17
17
|
|
18
18
|
In this example, `Team` refers to the immediate parent of the `Project` resource. For more details, just run `bin/super-scaffold` or [read the documentation](/docs/super-scaffolding.md).
|
19
19
|
|
20
|
-
2. Use `rails g migration` and `bin/super-scaffold` to add a new field to a model you've already scaffolded:
|
20
|
+
2. Use `rails g migration` and `bin/super-scaffold crud-field` to add a new field to a model you've already scaffolded:
|
21
21
|
|
22
22
|
```
|
23
23
|
rails g migration add_description_to_projects description:text
|
@@ -32,7 +32,7 @@ If you're using Bullet Train for the first time, begin by learning these five im
|
|
32
32
|
- Selecting "Inspect Element".
|
33
33
|
- Looking for the `<!-- BEGIN ... -->` comment above the element you've selected.
|
34
34
|
|
35
|
-
4. Figure out the full
|
35
|
+
4. Figure out the full I18n translation key of any string on the page by adding `?show_locales=true` to the URL.
|
36
36
|
|
37
37
|
5. Use `bin/resolve` to figure out where framework or theme things are coming from and eject them if you need to customize something locally:
|
38
38
|
|
data/docs/i18n.md
CHANGED
@@ -8,7 +8,7 @@ We override the native I18n translation method to automatically include the curr
|
|
8
8
|
The following are the details for David’s Membership on Your Team.
|
9
9
|
```
|
10
10
|
|
11
|
-
The view can be found here in the `bullet_train
|
11
|
+
The view can be found here in the `bullet_train` gem:<br/>[bullet_train-core/bullet_train/app/views/account/memberships/show.html.erb](https://github.com/bullet-train-co/bullet_train-core/blob/fab77efab57126c083e0041f97c0e716560a2ffe/bullet_train/app/views/account/memberships/show.html.erb#L16)<br/>
|
12
12
|
<br/>
|
13
13
|
Looking at the view, you can see we are only passing a key to the translation method for I18n to process:
|
14
14
|
|
@@ -16,7 +16,7 @@ Looking at the view, you can see we are only passing a key to the translation me
|
|
16
16
|
<%= t('.description') %>
|
17
17
|
```
|
18
18
|
|
19
|
-
However, looking at the [locale itself](https://github.com/bullet-train-co/bullet_train-
|
19
|
+
However, looking at the [locale itself](https://github.com/bullet-train-co/bullet_train-core/blob/fab77efab57126c083e0041f97c0e716560a2ffe/bullet_train/config/locales/en/memberships.en.yml#L82), you can see that the string takes two variables, `memberships_possessive` and `team_name`, to complete the string:
|
20
20
|
```yaml
|
21
21
|
description: The following are the details for %{memberships_possessive} Membership on %{team_name}.
|
22
22
|
```
|
@@ -26,6 +26,6 @@ Usually, you would pass the variable as a keyword argument:
|
|
26
26
|
t('.description', memberships_possessive: memberships_possessive, team_name: current_team.name)
|
27
27
|
```
|
28
28
|
|
29
|
-
However, in Bullet Train, we override the original translation method to include variable names like this automatically in our locales. Check out the [locale helper](https://github.com/bullet-train-co/bullet_train-
|
29
|
+
However, in Bullet Train, we override the original translation method to include variable names like this automatically in our locales. Check out the [locale helper](https://github.com/bullet-train-co/bullet_train-core/blob/main/bullet_train/app/helpers/account/locale_helper.rb) to get a closer look at how we handle strings for internationalization. For example, the two variables above are generated by the method `model_locales` in the locale helper.
|
30
30
|
|
31
31
|
You can find more information in the [indirection documentation](indirection) about using `bin/resolve` and logs to pinpoint where your locales are coming from.
|
data/docs/indirection.md
CHANGED
@@ -61,13 +61,15 @@ Would you like to open `/Users/andrewculver/.rbenv/versions/3.1.2/lib/ruby/gems/
|
|
61
61
|
y
|
62
62
|
```
|
63
63
|
|
64
|
-
You may also want to consider using `bin/
|
64
|
+
You may also want to consider using `bin/hack`, which will clone the Bullet Train core packages to `local/bullet_train-core` within your main application's root directory. Running this command will also automatically link the packages to your main application and open bullet_train-core in the code editor for you, so you can start using the cloned repository and make changes to your main application right away.
|
65
|
+
|
66
|
+
To revert back to using the original gems, run `bin/hack --reset`. You can link up to your local packages at any time with `bin/hack --link`.
|
65
67
|
|
66
68
|
Note that in the example above, the view in question isn't actually coming from the application repository. Instead, it's being included from the `bullet_train-themes-light` package. For further instructions on how to customize it, see [Overriding Framework Defaults](/docs/overriding.md).
|
67
69
|
|
68
70
|
### Drilling Down on Translation Keys
|
69
71
|
|
70
|
-
Even in vanilla Rails applications, extracting strings from view files into
|
72
|
+
Even in vanilla Rails applications, extracting strings from view files into I18n translation YAML files introduces a layer of indirection. Bullet Train tries to improve the resulting DX with a couple of tools that make it easier to figure out where a translation you see in your browser is coming from.
|
71
73
|
|
72
74
|
#### Show Translation Keys in the Browser with `?show_locales=true`
|
73
75
|
|
@@ -75,11 +77,11 @@ You can see the full translation key of any string on the page by adding `?show_
|
|
75
77
|
|
76
78
|
#### Log Translation Keys to the Console with `?log_locales=true`
|
77
79
|
|
78
|
-
You can also log all the translation
|
80
|
+
You can also log all the translation keys for anything being rendered to the console by adding `?log_locales=true` to the request URL. This can make it easier to copy and paste translation keys for strings that are rendered in non-selectable UI elements.
|
79
81
|
|
80
82
|
#### Resolving Translation Keys with `bin/resolve`
|
81
83
|
|
82
|
-
Once you have the full
|
84
|
+
Once you have the full I18n translation key, you can use `bin/resolve` to figure out which package and file it's coming from. At that point, if you need to customize it, you can also use the `--eject` option to copy the framework for customization in your local application:
|
83
85
|
|
84
86
|
```
|
85
87
|
bin/resolve en.account.onboarding.user_details.edit.header --eject --open
|
data/docs/namespacing.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Namespacing in Bullet Train
|
2
2
|
|
3
3
|
## The `Account` Namespace for Controllers and Views
|
4
|
-
Bullet Train comes preconfigured with an `Account`
|
4
|
+
Bullet Train comes preconfigured with an `Account` namespace for controllers and views. This is the place where Super Scaffolding will, by default, put new resource views and controllers. The intention here is to ensure that in systems that have both authenticated resource workflows and public-facing resources, those two different facets of the application are served by separate resource views and controllers. (By default, public-facing resources would be in the `Public` namespace.)
|
5
5
|
|
6
6
|
## Alternative Authenticated Namespaces
|
7
7
|
In Bullet Train applications with [multiple team types](/docs/teams.md), you may find it helpful to introduce additional controller and view namespaces to represent and organize user interfaces and experiences for certain team types that vary substantially from the `Account` namespace default. In Super Scaffolding, you can specify a namespace other than `Account` with the `--namespace` option, for example:
|
data/docs/onboarding.md
CHANGED
@@ -17,25 +17,25 @@ Each of the following files exist within their own respective Bullet Train packa
|
|
17
17
|
|
18
18
|
### Controllers
|
19
19
|
- `ensure_onboarding_is_complete` in `bullet_train/app/controllers/account/application_controller.rb`
|
20
|
-
- `bullet_train-
|
21
|
-
- `bullet_train-
|
20
|
+
- `bullet_train-core/bullet_train/app/controllers/account/onboarding/user_details_controller.rb`
|
21
|
+
- `bullet_train-core/bullet_train/app/controllers/account/onboarding/user_email_controller.rb`
|
22
22
|
|
23
23
|
### Views
|
24
|
-
- `bullet_train-
|
25
|
-
- `bullet_train-
|
24
|
+
- `bullet_train-core/bullet_train/app/views/account/onboarding/user_details/edit.html.erb`
|
25
|
+
- `bullet_train-core/bullet_train/app/views/account/onboarding/user_email/edit.html.erb`
|
26
26
|
|
27
27
|
### Models
|
28
|
-
- `user#details_provided?` in `bullet_train
|
28
|
+
- `user#details_provided?` in `bullet_train/app/models/concerns/users/base.rb`
|
29
29
|
|
30
30
|
### Routes
|
31
|
-
- `namespace :onboarding` in `bullet_train-
|
31
|
+
- `namespace :onboarding` in `bullet_train-core/bullet_train/config/routes.rb` and `bullet_train/config/routes.rb`
|
32
32
|
|
33
33
|
## Adding Additional Steps
|
34
34
|
Although you can implement onboarding steps from scratch, we always just copy and paste one of the existing steps as a starting point, like so:
|
35
35
|
|
36
|
-
1. Copy, rename, and modify of the existing onboarding controllers.
|
36
|
+
1. Copy, rename, and modify all of the existing onboarding controllers.
|
37
37
|
2. Copy, rename, and modify the corresponding `edit.html.erb` view.
|
38
|
-
3. Copy and rename the route entry in `bullet_train-
|
38
|
+
3. Copy and rename the route entry in `bullet_train-core/bullet_train/config/routes.rb`.
|
39
39
|
4. Add the appropriate gating logic in `ensure_onboarding_is_complete` in `bullet_train/app/controllers/account/application_controller.rb`
|
40
40
|
|
41
41
|
Onboarding steps aren't limited to targeting `User` models. It's possible to add onboarding steps to help flesh out team `Membership` records or `Team` records as well. You can use this pattern for setting up any sort of required data for either the user or the team.
|
data/docs/overriding.md
CHANGED
@@ -18,4 +18,4 @@ class User < ApplicationRecord
|
|
18
18
|
end
|
19
19
|
```
|
20
20
|
|
21
|
-
In this case, for most customizations or extensions you would want to make, you don't need to eject `Users::
|
21
|
+
In this case, for most customizations or extensions you would want to make, you don't need to eject `Users::Base` into your local repository. Instead, you can simply re-define methods from that concern in your local `User` model after the inclusion of the concern.
|
data/docs/permissions.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
Bullet Train leans heavily on [CanCanCan](https://github.com/CanCanCommunity/cancancan) for implementing authorization and permissions. (We’re also proud sponsors of its ongoing maintenance.) The original CanCan library by Ryan Bates was, in our opinion, a masterpiece and a software engineering marvel that has stood the test of time. It's truly a diamond among Ruby Gems. If you're not already familiar with CanCanCan, you should [read its documentation](https://github.com/CanCanCommunity/cancancan) to get familiar with its features and DSL.
|
5
5
|
|
6
6
|
## Bullet Train Roles
|
7
|
-
Over many years of successfully implementing applications with CanCanCan, it became apparent to us that a supplemental level of abstraction could help streamline and simplify the definition of many common permissions, especially in large applications. We've since extracted this functionality into [a standalone Ruby Gem](https://github.com/bullet-train-co/bullet_train-roles) and moved the documentation that used to be here into [the README for that project](https://github.com/bullet-train-co/bullet_train-roles). Should you encounter situations where this abstraction doesn't meet your specific needs, you can always implement the permissions you need using standard CanCanCan directives in `app/models/ability.rb`.
|
7
|
+
Over many years of successfully implementing applications with CanCanCan, it became apparent to us that a supplemental level of abstraction could help streamline and simplify the definition of many common permissions, especially in large applications. We've since extracted this functionality into [a standalone Ruby Gem](https://github.com/bullet-train-co/bullet_train-core/tree/main/bullet_train-roles) and moved the documentation that used to be here into [the README for that project](https://github.com/bullet-train-co/bullet_train-core/tree/main/bullet_train-roles). Should you encounter situations where this abstraction doesn't meet your specific needs, you can always implement the permissions you need using standard CanCanCan directives in `app/models/ability.rb`.
|
8
8
|
|
9
9
|
## Additional Notes
|
10
10
|
|
data/docs/seeds.md
CHANGED
@@ -29,7 +29,7 @@ end
|
|
29
29
|
We do this so Bullet Train applications can re-use the logic in `db/seeds.rb` for three purposes:
|
30
30
|
|
31
31
|
1. Set up new local development environments.
|
32
|
-
2. Ensure the test suite has the same configuration for features whose configuration is backed by Active Record (e.g. [
|
32
|
+
2. Ensure the test suite has the same configuration for features whose configuration is backed by Active Record (e.g. [outgoing webhooks](/docs/webhooks/outgoing.md)).
|
33
33
|
3. Ensure any updates to the baseline configuration that have been tested both locally and in CI are the exact same updates being executed in production upon deploy.
|
34
34
|
|
35
35
|
This makes `db/seeds.rb` a single source of truth for this sort of baseline data, instead of having this concern spread and sometimes duplicated across `db/seeds.rb`, `db/migrations/*`, and `test/fixtures`.
|
data/docs/testing.md
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# Automated Test Suite
|
2
2
|
All of Bullet Train’s core functionality is verifiable using the provided test suite. This foundation of headless browser integration tests took a ton of time to write, but they can give you the confidence and peace of mind that you haven't broken any key functionality in your application before a deploy.
|
3
3
|
|
4
|
-
You can run the test suite with the following
|
4
|
+
You can run the test suite with the following commands in your shell:
|
5
5
|
|
6
6
|
```
|
7
|
+
rails test
|
7
8
|
rails test:system
|
8
9
|
```
|
9
10
|
|
data/docs/themes.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Themes
|
2
2
|
|
3
|
-
Bullet Train has a theme subsystem designed to allow you the flexibility to either extend or completely replace the stock “Light” UI
|
3
|
+
Bullet Train has a theme subsystem designed to allow you the flexibility to either extend or completely replace the stock “Light” UI theme.
|
4
4
|
To reduce duplication of code across themes, Bullet Train implements the following three packages:
|
5
5
|
1. `bullet_train-themes`
|
6
6
|
2. `bullet_train-themes-tailwind_css`
|
@@ -10,12 +10,16 @@ This is where all of Bullet Train's standard views are contained.
|
|
10
10
|
|
11
11
|
## Adding a New Theme (ejecting standard views)
|
12
12
|
|
13
|
-
If you want to add a new theme, you can use the following command.
|
14
|
-
|
13
|
+
If you want to add a new theme, you can use the following command. For example, let's make a new theme called "foo":
|
14
|
+
```
|
15
|
+
> rake bullet_train:themes:light:eject[foo]
|
16
|
+
```
|
17
|
+
|
18
|
+
This will copy all of the standard views from `bullet_train-themes-light` to `app/views/themes/` and configure your application to use the new theme.
|
15
19
|
|
16
20
|
After running this command, you will see that a few other files are edited to use this new theme. Whenever switching a theme, you will need to make the same changes to make sure your application is running with the theme of your choice.
|
17
21
|
|
18
|
-
You can also pass an annotated path to a view after running `bin/resolve` to eject individual views to your application.
|
22
|
+
You can also pass an annotated path to a view after running `bin/resolve --interactive` to eject individual views to your application.
|
19
23
|
|
20
24
|
## Theme Component Usage
|
21
25
|
|
@@ -25,21 +29,24 @@ To use a theme component, simply include it from "within" `shared` like so:
|
|
25
29
|
<%= render 'shared/fields/text_field', method: :text_field_value %>
|
26
30
|
```
|
27
31
|
|
28
|
-
We say "within" because while a `shared` view partial directory does exist, the referenced `shared/fields/_text_field.html.erb` doesn't actually exist within it. Instead, the theme engine picks up on `shared` and
|
32
|
+
We say "within" because while a `shared` view partial directory does exist, the referenced `shared/fields/_text_field.html.erb` doesn't actually exist within it. Instead, the theme engine picks up on `shared` and then works its way through the theme directories to find the appropriate match.
|
29
33
|
|
30
34
|
### Dealing with Indirection
|
31
35
|
|
32
36
|
This small piece of indirection buys us an incredible amount of power in building and extending themes, but as with any indirection, it could potentially come at the cost of developer experience. That's why Bullet Train includes additional tools for smoothing over this experience. Be sure to read the section on [dealing with indirection](./indirection.md).
|
33
37
|
|
34
|
-
## Theme Configuration
|
38
|
+
## Restoring Theme Configuration
|
35
39
|
|
36
|
-
Your application will automatically be configured to use your new theme whenever you run the eject command.
|
40
|
+
Your application will automatically be configured to use your new theme whenever you run the eject command. You can run the below command to re-install the standard light theme.
|
41
|
+
```
|
42
|
+
> rake bullet_train:themes:light:install
|
43
|
+
```
|
37
44
|
|
38
45
|
## Additional Guidance and Principles
|
39
46
|
|
40
47
|
### Should you extend or replace?
|
41
48
|
|
42
|
-
For most development projects, the likely best path for customizing the UI is to extend “Light” or another complete Bullet Train theme. It’s difficult to convey how many hours have gone into making the Bullet Train themes complete and coherent from end to end. Every type of field partial, all the third-party libraries, all the responsiveness scenarios, etc. It
|
49
|
+
For most development projects, the likely best path for customizing the UI is to extend “Light” or another complete Bullet Train theme. It’s difficult to convey how many hours have gone into making the Bullet Train themes complete and coherent from end to end. Every type of field partial, all the third-party libraries, all the responsiveness scenarios, etc. It has taken many hours of expert time.
|
43
50
|
|
44
51
|
Extending an existing theme is like retaining an option on shipping. By extending a theme that is already complete, you allow yourself to say “enough is enough” at a certain point and just living with some inherited defaults in exchange for shipping your product sooner. You can always do more UI work later, but it doesn’t look unpolished now!
|
45
52
|
|
@@ -63,11 +70,11 @@ On the other hand, if you decide to try to build a theme from the ground up, you
|
|
63
70
|
<% end %>
|
64
71
|
```
|
65
72
|
|
66
|
-
This allows the theme engine to resolve which theme in the inheritance chain
|
73
|
+
This allows the theme engine to resolve which theme in the inheritance chain will include the `box` partial. For example:
|
67
74
|
|
68
|
-
- It might come from the “Light” theme today, but if you switch to the “Bold” theme later, it’ll
|
75
|
+
- It might come from the “Light” theme today, but if you switch to the “Bold” theme later, it’ll start pulling it from there.
|
69
76
|
- If you start extending “Light”, you can override its `box` implementation and your application will pick up the new customized version from your theme automatically.
|
70
|
-
- If (hypothetically) `box`
|
77
|
+
- If (hypothetically) `box` becomes generalized and moves into the parent “Tailwind CSS” theme, your application would pick it up from the appropriate place.
|
71
78
|
|
72
79
|
### Let your designer name their theme.
|
73
80
|
|