fae-rails 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bddf9ecc83c29722d6937f621e66cfa28fcfbd09
4
- data.tar.gz: 8c72a5dfb38f6e70a61ca1beba3ef0b979f2453e
3
+ metadata.gz: 7e4e2e9807100f19e49edaaee29e6a7d9888f7f9
4
+ data.tar.gz: c357c40edd30cbff37e17efdf919c578c4565c4a
5
5
  SHA512:
6
- metadata.gz: 7a3a805eaeb452074096b8cd7dd320df41331dcac0ee73f54a6c10f24390a08960a67812004b8590e12497aff07c49bdf38ad4a49c113912490ec63791e301c3
7
- data.tar.gz: 87378f7246f0607c0b8fd3f9ef3dd8be4fbb7a37068dd130752e5555da504d855415fee2668a371e5327af87062936f5812ecf762a4fe98d354d6d14c58cc0a4
6
+ metadata.gz: fb295b46e0bc983487229d8f7105314c94c5975215fbf2188dff4792ac7710deb97882eed162882d71539af24e82e50e861aebf5a058354ab03a438fc8c0b560
7
+ data.tar.gz: 80617c4bbca334d9f02dda18410772c30b9d3c3a91bca061736d78f4b5c95c39eb01c21d7c1ce80ece0cd311f6f27db825d008a03bf314d33610bd55f0dd4d53
data/README.md CHANGED
@@ -1,34 +1,25 @@
1
1
  # Meet Fae
2
2
 
3
- Fae is an admin engine for Rails unlike any other. Like most Rails admins, Fae provides all the basics to get you up and running: authentication, a responsive UI, form element and workflows. But unlike other admins, Fae's methodology is based around generators and a DSL over configuration. This allows you to get to a working admin very quickly, but gives you the flexibility to override any piece you need.
3
+ ![Shippable Status](https://img.shields.io/shippable/5522ec125ab6cc1352b9bb77.svg)
4
+ [![Code Climate](https://codeclimate.com/github/wearefine/fae/badges/gpa.svg)](https://codeclimate.com/github/wearefine/fae)
5
+
6
+ Fae is CMS for Rails unlike any other. Like most Rails CMS engines, Fae provides all the basics to get you up and running: authentication, a responsive UI, form element and workflows. But unlike other CMS engines, Fae's methodology is based around generators and a DSL over configuration. This allows you to get to a working CMS very quickly, but gives you the flexibility to customize any piece you need.
4
7
 
5
8
  Fae requires Rails >= 4.1.
6
9
 
7
10
  ## Documentation
8
11
 
9
- ### Installation and Usage
10
-
11
- https://bitbucket.org/wearefine/fae/src/master/docs/index.md
12
-
13
- ### Form and View Helpers
14
-
15
- https://bitbucket.org/wearefine/fae/src/master/docs/helpers.md
16
-
17
- ### Upgrading Guide
18
-
19
- https://bitbucket.org/wearefine/fae/src/master/docs/upgrading.md
20
-
21
- ### Changelog
22
-
23
- https://bitbucket.org/wearefine/fae/src/master/CHANGELOG.md
24
-
25
- ### Contibuting and Maintenance
26
-
27
- https://bitbucket.org/wearefine/fae/src/master/CONTRIBUTING.md
12
+ * [Installation](docs/index.md)
13
+ * [Usage](docs/usage.md)
14
+ * [Customization](docs/customization.md)
15
+ * [Form and View Helpers](docs/helpers.md)
16
+ * [Upgrading Guide](docs/upgrading.md)
17
+ * [Changelog](CHANGELOG.md)
18
+ * [Contributing and Maintenance](CONTRIBUTING.md)
28
19
 
29
- ### License
20
+ ## License
30
21
 
31
- https://bitbucket.org/wearefine/fae/src/master/LICENSE
22
+ [MIT](LICENSE)
32
23
 
33
24
 
34
25
 
data/config/deploy.rb CHANGED
@@ -1,5 +1,5 @@
1
- set :application, 'fae.afinedevelopment.com'
2
- set :repo_url, 'git@bitbucket.org:wearefine/fae.git'
1
+ set :application, 'Fae Dummy'
2
+ set :repo_url, 'git@github.com:wearefine/fae.git'
3
3
 
4
4
  set :scm, :git
5
5
 
@@ -17,7 +17,7 @@ set :keep_releases, 5
17
17
  # variable for forked version of capistrano-rails
18
18
  set :rails_path, 'spec/dummy'
19
19
 
20
- server 'fae.afinedevelopment.com',
20
+ server '54.164.40.189',
21
21
  user: 'fae',
22
22
  roles: %w{web app db},
23
23
  port: 8022,
@@ -0,0 +1,471 @@
1
+ # Customization
2
+
3
+ * [Overview](#overview)
4
+ * [Multiple Language Support](#multiple-language-support)
5
+ * [Filtering](#filtering)
6
+ * [Change Tracker](#change-tracker)
7
+ * [CSS Classes](#css-classes)
8
+ * [Cloning](#cloning)
9
+
10
+ ---
11
+
12
+ # Overview
13
+
14
+ Fae is meant to allow some radically customization. You can stray completely from Fae's generators and helpers and build your own admin section. However, if you stray from Fae standards you lose the benefit of future bug fixes and feature Fae may provide.
15
+
16
+ If you need to create custom classes, it's recommended you inherit from a Fae class and if you need to update a Fae class, look for a concern to inject into first.
17
+
18
+ ## Fae Model Concerns
19
+
20
+ Each one of Fae's models has a built in concern. You can create that concern in your application to easily inject logic into built in models, following Rails' concern pattern. E.g. adding methods to `app/models/concerns/fae/role_concern.rb` will make them accessible to `Fae::Role`.
21
+
22
+ ### Example: Adding OAuth2 logic to Fae::User
23
+
24
+ Say we wanted to add a lookup class method to `Fae::User` to allow for Google OAuth2 authentication. We simply need to add the following to our application:
25
+
26
+ `app/models/concerns/fae/user_concern.rb`
27
+ ```ruby
28
+ module Fae
29
+ module UserConcern
30
+ extend ActiveSupport::Concern
31
+
32
+ included do
33
+ # overidde Fae::User devise settings
34
+ devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable, omniauth_providers: [:google_oauth2]
35
+ end
36
+
37
+ module ClassMethods
38
+ # add new class method to Fae::User
39
+ def self.find_for_google_oauth2(access_token, signed_in_resource = nil)
40
+ data = access_token.info
41
+ user = Fae::User.find_by_email(data['email'])
42
+
43
+ unless user
44
+ user = Fae::User.create(
45
+ first_name: data['name'],
46
+ email: data['email'],
47
+ role_id: 3,
48
+ active: 1,
49
+ password: Devise.friendly_token[0, 20]
50
+ )
51
+ end
52
+ user
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+ ```
59
+
60
+ ### Available Fae Concerns
61
+
62
+ | Fae Class | Concern Path |
63
+ |----------------------------|--------------|
64
+ | Fae::ApplicationController | app/controllers/concerns/application_controller_concern.rb |
65
+ | Fae::File | app/models/concerns/file_concern.rb |
66
+ | Fae::Image | app/models/concerns/image_concern.rb |
67
+ | Fae::Option | app/models/concerns/option_concern.rb |
68
+ | Fae::StaticPage | app/models/concerns/static_page_concern.rb |
69
+ | Fae::TextArea | app/models/concerns/text_area_concern.rb |
70
+ | Fae::TextField | app/models/concerns/text_field_concern.rb |
71
+ | Fae::User | app/models/concerns/user_concern.rb |
72
+
73
+
74
+ ## Overriding Classes
75
+
76
+ If there's no way to inherit from or inject into a Fae class, your last effort would be to override it. To do that, simply copy the Fae class into your application in the same path found in Fae and customize it from there.
77
+
78
+ E.g. if you need to customize Fae's `image_controller.rb`, copy the file from Fae into your application at `app/controllers/fae/image_controller.rb`.
79
+
80
+ ## Overriding Uploaders
81
+
82
+ If you need to override the uplodaers `Fae::Image` and `Fae::File` use, you can use the method in the previous section. To customize the `Fae::ImageUploader` just copy file to `app/uploaders/fae/image_uploader.rb` and make your updates.
83
+
84
+ This is handy when you need to update the `extension_white_list` or set your own resizing logic.
85
+
86
+ ## Custom JS/CSS
87
+
88
+ Fae creates two files in your assets pipeline that allow custom JS and CSS in your admin.
89
+
90
+ ### fae.js
91
+
92
+ `app/assets/javascripts/fae.js` compiles into `fae/application.js`. As noted in the file, you can use it as a mainfest (to add a lot of JS) or to simply add JS directly to.
93
+
94
+ #### Example: fae.js as a Manifest File
95
+
96
+ ```JavaScript
97
+ // This file is compiled into fae/application.js
98
+ // use this as another manifest file if you have a lot of javascript to add
99
+ // or just add your javascript directly to this file
100
+ //
101
+ //= require admin/plugins
102
+ //= require admin/main
103
+ ```
104
+
105
+ ### fae.scss
106
+
107
+ `app/assets/stylesheets/fae.scss` compiles into `fae/application.css`. Styles added to this files will be declared before other Fae styles. This file also provide a SCSS variable for Fae's highlight color: `$c-custom-highlight` (which defaults to #31a7e6).
108
+
109
+ ```CSS
110
+ // Do Not Delete this page! FAE depends on it in order to set its highlight color.
111
+ // $c-custom-highlight: #000;
112
+ ```
113
+
114
+ ## Overriding The Landing Page
115
+
116
+ If you want to ignore the default dashboard and make one of your views the landing page you can add a redirect route in your Fae namespace.
117
+
118
+ `config/routes.rb`
119
+ ```ruby
120
+ # ...
121
+ namespace :admin do
122
+ get '/', to: redirect('/admin/people')
123
+ # ...
124
+ ```
125
+
126
+ ---
127
+
128
+ # Multiple Language Support
129
+
130
+ Fae support a language nav that makes managing content in multiple languages easy. The language nav will display all available languages. Clicking a specific language will only display fields specific to that language.
131
+
132
+ ## Configure
133
+
134
+ To setup the language nav first define all languages Fae will be managing content in.
135
+
136
+ `config/initializers/fae.rb`
137
+ ```ruby
138
+ config.languages = {
139
+ en: 'English',
140
+ zh: 'Chinese',
141
+ ja: 'Japanese'
142
+ }
143
+ ```
144
+
145
+ The convention of this hash is important as the keys with have to match the database column suffixes of the specific language fields. The values will be used as the link text in the language nav.
146
+
147
+ ## Database Column Naming
148
+
149
+ As mentioned above, the column names of fields supporting multiple languages will have to follow this convention:
150
+
151
+ ```
152
+ "#{attribute_name}_#{language_abbreviation}`
153
+ ```
154
+
155
+ E.g. the english version of the title attribute would be `title_en`.
156
+
157
+ Using Fae's generators let's quickly scaffold a model that supports multiple languages (columns without suffixes will be treated normally:
158
+
159
+ ```bash
160
+ $ rails g fae:scaffold Person name title_en title_zh title_ja intro_en:text intro_zh:text intro_ja:text
161
+ ```
162
+
163
+ ## Language Nav Partial
164
+
165
+ Then finally, you'll need to add the `fae/shared/language_nav` partial to the form, as the first child of `section.main_content-header`:
166
+
167
+ `app/views/admin/people/_form.html.slim`
168
+ ```slim
169
+ = simple_form_for(['admin', @item]) do |f|
170
+ section.main_content-header
171
+
172
+ == render 'fae/shared/language_nav'
173
+
174
+ .main_content-header-wrapper
175
+ // ...
176
+ ```
177
+
178
+ ---
179
+
180
+ # Filtering
181
+
182
+ If you need to filter your content on your table views, Fae provides a system and helpers to do so.
183
+
184
+ Using the helpers provided, the filter form will POST to a filter action inherited from `Fae::BaseController`. You can override this action, but by default it will pass the params to a class method in your model called `filter`. It's then up you to scope the data that gets returned and rendered in the table.
185
+
186
+ Let's walk through an example. Using the `Person` model from above, let's say a person `belongs_to :company` and `has_many :groups`. We'll want to use select filters for companies and groups, and a keyword search to filter by people and company name.
187
+
188
+ ## Route
189
+
190
+ First, we'll need to add `post 'filter', on: :collection` to our `people` resources:
191
+
192
+ `config/routes.rb`
193
+ ```ruby
194
+ resources :people do
195
+ post 'filter', on: :collection
196
+ end
197
+ ```
198
+
199
+ ## View Helpers
200
+
201
+ Next we'll add the form to our view as the first child of `.main_content-section-area`:
202
+
203
+ `app/views/admin/people/index.html.slim`
204
+ ```slim
205
+ // ...
206
+ .main_content-section-area
207
+
208
+ == fae_filter_form do
209
+ == fae_filter_select :company
210
+ == fae_filter_select :groups
211
+
212
+ table.index_table.main_table-sort_columns
213
+ // ...
214
+ ```
215
+
216
+ The search field is built into `fae_filter_form`, but we'll need to provide a `fae_filter_select` for each select element in our filter bar.
217
+
218
+ Full documentation on both helpers can be found in the [helpers.md](helpers.md).
219
+
220
+ ## Class Methods
221
+
222
+ Finally we need to define our class methods to scope the `Person` class. This data will be assigned to `@items` and injected into the table via AJAX.
223
+
224
+ ### filter(params)
225
+
226
+ `ModelName#filter(params)` will be the scope when data is filtered. The `params` passed in will be the data directly from the `fae_filter_select` helpers we defined, plus `params['search']` from the seach field.
227
+
228
+ From the form above we can assume our params look like this:
229
+
230
+ ```ruby
231
+ {
232
+ 'search' => 'text from search field',
233
+ 'company' => 12, # value from company select
234
+ 'groups' => 3 # value from groups select
235
+ }
236
+ ```
237
+
238
+ So let's use that data to craft our class method.
239
+
240
+ `app/models/person.rb`
241
+ ```ruby
242
+ def self.filter(params)
243
+ # build conditions if specific params are present
244
+ conditions = {}
245
+ conditions[:company_id] = params['company'] if params['company'].present?
246
+ conditions['groups.id'] = params['groups'] if params['groups'].present?
247
+
248
+ # use good 'ol MySQL to seach if search param is present
249
+ search = []
250
+ if params['search'].present?
251
+ search = ["people.name LIKE ? OR companies.name LIKE ?", "%#{params['search']}%", "%#{params['search']}%"]
252
+ end
253
+
254
+ # apply conditions and search from above to our scope
255
+ order(:name)
256
+ .includes(:company, :groups).references(:company, :groups)
257
+ .where(conditions).where(search)
258
+ end
259
+ ```
260
+
261
+ ### filter_all
262
+
263
+ There's also a `ModelName#filter_all` which is called when you reset the filter form. This defaults to the `for_fae_index` scope, but you can override it if you need to.
264
+
265
+ ```ruby
266
+ def self.filter_all
267
+ where.not(name: 'John').order(:position)
268
+ end
269
+ ```
270
+
271
+ ---
272
+
273
+ # Change Tracker
274
+
275
+ Fae has a build in system to track the changes of the records in your admin. By default it's on, tracking the last 15 times a record has been changed. Make sure any model you want to track has `include Fae::BaseModelConcern` at the top.
276
+
277
+ For each change the tracker tracks what kind of change it is (create, update or delete), what attributes were changed, who changed it and when it happened.
278
+
279
+ ## Global Options
280
+
281
+ You can turn off tracking altogether or update how many revisions the tracker keeps with the following options set in `config/initializers/fae.rb`.
282
+
283
+ | key | type | default | description |
284
+ | --- | ---- | ------- | ----------- |
285
+ | track_changes | boolean | true | Determines whether or not to track changes on your objects
286
+ | tracker_history_length | integer | 15 | Determines the max number of changes logged per object
287
+
288
+ ### Example
289
+
290
+ `config/initializers/fae.rb`
291
+ ```ruby
292
+ Fae.setup do |config|
293
+
294
+ config.tracker_history_length = 10
295
+
296
+ end
297
+ ```
298
+
299
+ ## Blacklisting Models and Attributes
300
+
301
+ If you want to turn off tracking on specific attibutes or a model altogether you can define an optional instance method `fae_tracker_blacklist`.
302
+
303
+ ### Blacklisting a Model
304
+
305
+ To blacklist an entire model have `fae_tracker_blacklist` return 'all'.
306
+
307
+ ```ruby
308
+ class DontTrackMe < ActiveRecord::Base
309
+ include Fae::BaseModelConcern
310
+
311
+ def fae_tracker_blacklist
312
+ 'all'
313
+ end
314
+ end
315
+ ```
316
+
317
+ ### Blacklisting Attributes
318
+
319
+ To blacklist specific attributes have 'fae_tracker_blacklist' return an array of attribute names as symbols or strings.
320
+
321
+ ```ruby
322
+ class DontTrackMe < ActiveRecord::Base
323
+ include Fae::BaseModelConcern
324
+
325
+ def fae_tracker_blacklist
326
+ [:position, :slug]
327
+ end
328
+ end
329
+ ```
330
+
331
+ ## Accessing the Tracked Changes
332
+
333
+ Each model that includes `Fae::BaseModelConcern` will have the following association:
334
+
335
+ ```
336
+ has_many :tracked_changes
337
+ ```
338
+
339
+ Each tracked change is a record of `Fae::Change` and has the following attrubtes available
340
+
341
+ | attribute | description |
342
+ | --------- | ----------- |
343
+ | `changeable` | a polymorphic association back to the changed record |
344
+ | `user` | an association to the user that updated the record |
345
+ | `change_type` | how the record was changed, options are: created, updated or deleted |
346
+ | `updated_attributes` | an array of attributes changed (for updated records only) |
347
+ | `updated_at` | when the change occured |
348
+
349
+ ### Example Usage
350
+
351
+ ```ruby
352
+ @item.tracked_changes.each do |change|
353
+ "This item was #{change.change_type} by #{change.user.first_name} on {change.updated_at}."
354
+ end
355
+ ```
356
+
357
+ ## Display Tracked Changes Table
358
+
359
+ Fae provides a partial to display tracked changes in an object's form. Read more about `render 'fae/shared/recent_changes'` here:
360
+
361
+ [helpers.md#markdown-header-recent_changes](helpers.md#markdown-header-recent_changes)
362
+
363
+ ---
364
+
365
+ # CSS Classes
366
+
367
+ ## Fixed position table headers
368
+
369
+ For extra long tables, add the class `sticky-table-header` to a `table` and scroll away. Multiple sticky tables can appear on one page.
370
+
371
+ ## Collapsible tables
372
+
373
+ Some pages have multiple tables that are easier to navigate if tables can be shown or hidden. Wrap each table in a `.collapsible` div and prepend an `h3` with the item's name and count. Example below and on the dummy app's `events/index` page.
374
+
375
+ ```slim
376
+ .main_content-section-area
377
+ .collapsible
378
+ h3 All Wine (#{@all_wine.length})
379
+ table.index_table
380
+ ....
381
+ .collapsible
382
+ h3 White & Sparkling Wine (#{@white_sparkling_wine.length})
383
+ table.index_table
384
+ ....
385
+ ```
386
+
387
+ For best results, include an Open/Close All toggle.
388
+
389
+ ```slim
390
+ .main_content-section-area
391
+ .collapsible-toggle Open All
392
+ .collapsible
393
+ ....
394
+ ```
395
+
396
+ ---
397
+
398
+ # Cloning
399
+
400
+ So you want to easily, automagically clone a record and its children? Lucky for you, we made it easy to do that! You're welcome.
401
+
402
+ ## Basic
403
+
404
+ The most basic implementation of this feature clones the record, all it's attributes (except id, created and updated at) and any belongs_to associations via foreign_keys. We also check for any uniqueness validators on your attributes and rename them to "attribute-#", starting at 2, for your convenience.
405
+
406
+ ## Add Buttons
407
+
408
+ You may add the clone button to the index, edit form, or both.
409
+
410
+ **Examples**
411
+
412
+ #### For Index
413
+
414
+ Add the following to your `thead`, usually after 'Delete':
415
+
416
+ ```slim
417
+ th class="main_table-header-clone" data-sorter="false" Clone
418
+ ```
419
+
420
+ And to your `tbody`:
421
+
422
+ ```slim
423
+ td = fae_clone_button item
424
+ ```
425
+
426
+ #### For Form
427
+
428
+ Simply pass `cloneable: true` into your form_buttons partial. You may also edit the default text 'Clone', by passing in `clone_button_text` and your own string.
429
+
430
+ ```ruby
431
+ render 'fae/shared/form_buttons', cloneable: true, clone_button_text: 'Duplicate Me!'
432
+ ```
433
+
434
+ That's all for basic set-up.
435
+
436
+ ## Advanced
437
+
438
+ If you want complete control over which attributes and associations are cloned, we wouldn't call you a control freak. We've baked in some nice simple methods to make this possible.
439
+
440
+ **Note:** Asset cloning is not currently supported, so if you try to pass in those associations, cloning will fail.
441
+
442
+ ## Whitelisting Attributes
443
+
444
+ If you want to whitelist attributes to be cloned, you may add the `attributes_for_cloning` method into your controller's private method. Just pass in an array of symbols and we will take care to only copy those attributes over.
445
+
446
+ **Note:** please make sure to include _everything_ that is required, or the record will fail to get created. You've been warned.
447
+
448
+ **Example**
449
+
450
+ ```ruby
451
+ def attributes_for_cloning
452
+ [:name, :slug, :description, :wine_id]
453
+ end
454
+ ```
455
+
456
+ ## Cloning Associations
457
+
458
+ Belongs_to associations are automatically copied over, unless you are whitelisting attributes and forget to/ purposely don't add it there. For the rest of the associations you may have (i.e. has_one, has_many, has_and_belongs_to_many, has_many_through), you may use the `associations_for_cloning` method by passing in array of symbols.
459
+
460
+ **Note:** Any images or files you have will be copied along, if you have included those relationships.
461
+
462
+ **Example**
463
+
464
+ ```ruby
465
+ def associations_for_cloning
466
+ [:aromas, :events]
467
+ end
468
+ ```
469
+
470
+ That's it! Happy cloning. :)
471
+