journea 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +8 -0
- data/README.md +131 -0
- data/Rakefile +26 -0
- data/app/controllers/journea/engine_controller.rb +19 -0
- data/app/controllers/journea/journeys_controller.rb +10 -0
- data/app/controllers/journea/steps_controller.rb +52 -0
- data/app/helpers/journea/form_helper.rb +25 -0
- data/app/models/journea/journey.rb +54 -0
- data/app/models/journea/journey_transition.rb +17 -0
- data/app/models/journea/keyvalue.rb +5 -0
- data/app/views/application/_back_link.html.haml +5 -0
- data/config/initializers/simple_form.rb +179 -0
- data/config/locales/simple_form.en.yml +31 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20161201153630_create_journey_transitions.rb +22 -0
- data/db/migrate/20161201162349_create_journeys_table.rb +10 -0
- data/db/migrate/20161202162350_create_keyvalues_table.rb +11 -0
- data/lib/generators/journea/install_generator.rb +76 -0
- data/lib/generators/journea/templates/assets/application.js +23 -0
- data/lib/generators/journea/templates/assets/application.scss +49 -0
- data/lib/generators/journea/templates/config/initializers/journea.rb +23 -0
- data/lib/generators/journea/templates/config/initializers/journea2.rb +24 -0
- data/lib/generators/journea/templates/controllers/pages_controller.rb.example +2 -0
- data/lib/generators/journea/templates/views/application.html.haml +20 -0
- data/lib/generators/journea/templates/views/pages/start.html.haml.example +12 -0
- data/lib/generators/journea/templates/views/shared/error_messages.html.haml.example +7 -0
- data/lib/generators/journea/templates/views/steps/step.html.haml.example +8 -0
- data/lib/journea.rb +25 -0
- data/lib/journea/data.rb +20 -0
- data/lib/journea/engine.rb +27 -0
- data/lib/journea/state_machine.rb +40 -0
- data/lib/journea/step.rb +32 -0
- data/lib/journea/version.rb +3 -0
- data/lib/simple_form_object.rb +146 -0
- data/lib/tasks/journea_tasks.rake +4 -0
- data/lib/templates/erb/scaffold/_form.html.erb +13 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +5 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/javascripts/cable.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/pages_controller.rb +4 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/steps/address_step.rb +4 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/app/views/pages/start.html.erb +1 -0
- data/spec/dummy/app/views/steps/address.html.erb +5 -0
- data/spec/dummy/app/views/steps/name.html.erb +5 -0
- data/spec/dummy/app/views/steps/phone_number.html.erb +0 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +34 -0
- data/spec/dummy/bin/update +29 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/config/application.rb +14 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +9 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +54 -0
- data/spec/dummy/config/environments/production.rb +86 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/journea.rb +8 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/puma.rb +47 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +42 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +57 -0
- data/spec/dummy/log/test.log +448 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/EA/EAR2KaBsPQau6HwaTGrxV7EGMwAWyS-4C8pGVDU1Z-Q.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/JZ/JZuPFgM2mLQgAHB-r7Pt_TdGW3DRWPrplT7xPjnCJSE.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LT/LTt1oE1gi9m65YRwUp78DuufkCOfi3sa3Qa05_ykADk.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Lj/LjRKOqtrClPtb97phuIWI7HHA8-p5J5nKHVE_zEycxo.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QM/QMxUWUtpFaqwG3RI9t3m38QtFAOvHpiY3LphKJiVRTc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/St/StFuOi5bd69ceiqz2D6EOCmRzHgwY0IxERsMfiCneGM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Vj/VjCUmI9pp5eD8BlYATbwJ4ZOk0438rwvtDrsttyWbfQ.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Wl/WlLcUIADXcUxaOt8Gq59uQbO0mquikyz7jxiJjXjhaI.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/YH/YHo__TrFq5y8rpx49T8d8ecyvMLbHFbnhz7IBV7pM98.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Zu/ZuLXgeX6x_Dx8sCUbzuTtWu42HzQXWe7eooTgsonTnc.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/aG/aG1tp1pv4kBiSKx9ixZH5xiRXH-rGa0Hi6sdl4SHw6g.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/aw/awTDtuorxLsRLIGEYCefR-PTN7yptoaGRLEk13vHVLA.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/b_/b_Itlk9QZZd7Rvf8kcA4yLP1R5Acu7jB-m1xQiSU0qE.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cW/cWHxYOqms7abJ-dzXyrn2G7nadJicU5kkC8SduS06yc.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cb/cbX7RFavWZoWojlrsXhsy4FN46UOfMwZYStkLHT5HJw.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/eY/eYTHvo0Wl2TD2vipDcJ966HHXGrA4ZlJaiA2DnftKhM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/f4/f4CpFuYmsdh1EvlFVjsl1WmM2QA9_z9AuOebEOw4mts.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gH/gHSjqTBRSW22rP9mSj8XW6huEXKpcIOehvF-2fvuShQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m0/m0smDeM83DcmOVpX9zos6AIX40E9Tf2j26tyvKFgMwc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mW/mWrwQwWUQpAlMCLQ8dGv5VkAXd-TxvAtB5WPg9l09-A.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mX/mX1nlsL_SWOB4y22W5FheRX0YEONKyOY7xUeIvRiHco.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/n_/n_xYqQYhwEMQknb3jFQnjlxxBE9TzMNHCdJ-bEyZFIw.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/nx/nxTv3sKVUQZADJyM3dPaVmUA78MIsMLD_K279yN_GsI.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/oA/oAtzk5ZeF7lWCwNufspgWqtv_dQN_n5GumFNB4ScfBE.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/rA/rACdJeX3jZNkhx4awGhdZeMdOfmARubkoVKVAZdwYog.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sC/sCEBZXwTjRpEzThf7YHzHNfkAupMVOx_Ko7WNMAFHS0.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/x7/x7PYh8DJvPykcEqpVab2vcY9-GFz-3cqtoMlRAu94Uc.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/yT/yTOf3QInGfDlRZlwZNDBLlbma19FQRHM035AKRxcRyw.cache +0 -0
- data/spec/features/journey_spec.rb +9 -0
- data/spec/lib/simple_form_object/attribute_spec.rb +74 -0
- data/spec/lib/simple_form_object/delegation_spec.rb +50 -0
- data/spec/lib/simple_form_object/model_spec.rb +90 -0
- data/spec/lib/steps_spec.rb +0 -0
- data/spec/requests/journeys_spec.rb +6 -0
- data/spec/spec_helper.rb +44 -0
- metadata +449 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b62952533c42e385316284af3e0e14a3e2ed34dd
|
4
|
+
data.tar.gz: bd27f82ed21bd76b53012e7f46a02f0d43981706
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: baa167b6d1f4b4a96b61bbc5d02650be086ecc0e316820df4a751ed3339dc59ec62b522de07aace8582f295a97dc8e411c8f231deebe2148854ee79ebbf63f38
|
7
|
+
data.tar.gz: b305cae30727a93ad44efd909cd145e13768f44e70b616e36e13988a2edd4dbd92cfa432e3852dc14d40b00bab1fe37987f6f3355b9cdea4cb0f7e5453a2b13f
|
data/LICENSE
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
The Open Government Licence (OGL) Version 3
|
2
|
+
|
3
|
+
Copyright (c) 2016 Environment Agency
|
4
|
+
|
5
|
+
This source code is licensed under the Open Government Licence v3.0. To view this
|
6
|
+
licence, visit www.nationalarchives.gov.uk/doc/open-government-licence/version/3
|
7
|
+
or write to the Information Policy Team, The National Archives, Kew, Richmond,
|
8
|
+
Surrey, TW9 4DU.
|
data/README.md
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# Journea (Alpha)
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/DEFRA/journea.svg?branch=master)](https://travis-ci.org/DEFRA/journea)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/DEFRA/journea/badges/gpa.svg)](https://codeclimate.com/github/DEFRA/journea)
|
5
|
+
[![Test Coverage](https://codeclimate.com/github/DEFRA/journea/badges/coverage.svg)](https://codeclimate.com/github/DEFRA/journea/coverage)
|
6
|
+
[![security](https://hakiri.io/github/DEFRA/journea/master.svg)](https://hakiri.io/github/DEFRA/journea/master)
|
7
|
+
[![Dependency Status](https://dependencyci.com/github/DEFRA/journea/badge)](https://dependencyci.com/github/DEFRA/journea)
|
8
|
+
[![Gem Version](https://badge.fury.io/rb/journea.svg)](https://badge.fury.io/rb/journea)
|
9
|
+
|
10
|
+
**Journea** is a Ruby on Rails engine (tested on Rails 5 only) which you can use to define steps and the transitions between them. Each step (or page) is tracked in a state machine, [Statesman](https://github.com/gocardless/statesman).
|
11
|
+
|
12
|
+
**Journea** handles rendering the views you design and the transitions between them are defined in an initializer.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add the gem to your gemfile.
|
17
|
+
|
18
|
+
Run the install generator and answer the questions
|
19
|
+
|
20
|
+
```
|
21
|
+
# Only use in new, fresh Rails projects
|
22
|
+
rails generate journea:install
|
23
|
+
```
|
24
|
+
|
25
|
+
## Getting started
|
26
|
+
|
27
|
+
For each step you need to setup a state in the state machine
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
# config/initializers/journea.rb
|
31
|
+
|
32
|
+
Journea.configure_steps do
|
33
|
+
step :import_or_export, initial: true
|
34
|
+
step :company_type
|
35
|
+
step :limited_company_details
|
36
|
+
step :company_address
|
37
|
+
step :finish
|
38
|
+
|
39
|
+
transition from: :import_or_export, to: :company_type
|
40
|
+
transition from: :company_type, to: [:limited_company_details, :company_address]
|
41
|
+
transition from: :limited_company_details, to: :company_address
|
42
|
+
transition from: :company_address, to: :finish
|
43
|
+
|
44
|
+
guard_transition(to: :limited_company_details) do |journea|
|
45
|
+
journea.data.is_limited_company?
|
46
|
+
end
|
47
|
+
|
48
|
+
after_transition(to: :finish) do |journea|
|
49
|
+
Mailer.application_details(journea.data).deliver
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
Each step can optionally have a step object, based on [simple form object](https://github.com/reinteractive-open/simple_form_object):
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
# app/steps/company_address_step.rb
|
58
|
+
|
59
|
+
class CompanyAddress < Journea::Step
|
60
|
+
attribute :address_line1, :string
|
61
|
+
attribute :address_line2, :string
|
62
|
+
attribute :city, :string
|
63
|
+
attribute :postcode, :string
|
64
|
+
attribute :is_business_address, :boolean
|
65
|
+
|
66
|
+
attribute :created_date, :datetime, default: Time.now
|
67
|
+
|
68
|
+
validates :address_line1, :address_line2, presence: true
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
And each step needs a view
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
|
76
|
+
# app/views/layouts/application.html.haml
|
77
|
+
|
78
|
+
# Optional back link helper can be used anywhere
|
79
|
+
|
80
|
+
= render 'back_link'
|
81
|
+
|
82
|
+
# app/views/steps/company_address.html.haml
|
83
|
+
|
84
|
+
.grid-row
|
85
|
+
.column-two-thirds
|
86
|
+
= simple_form_for @form do |f|
|
87
|
+
= render 'shared/error_messages'
|
88
|
+
|
89
|
+
%h1.heading-large What is your company address?
|
90
|
+
|
91
|
+
= f.input :address_line1
|
92
|
+
= f.input :address_line2, hint: 'Optional'
|
93
|
+
= f.input :city
|
94
|
+
= f.input :postcode
|
95
|
+
= f.input :is_business_address
|
96
|
+
|
97
|
+
= f.button :submit, 'Continue'
|
98
|
+
|
99
|
+
```
|
100
|
+
|
101
|
+
You can access data stored against the journey object like so
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
journey = Journea::Journey.find(1)
|
105
|
+
puts journey.data.certifcate_type
|
106
|
+
|
107
|
+
# or
|
108
|
+
puts @journea.data.certifcate_type
|
109
|
+
```
|
110
|
+
|
111
|
+
## Contributing to this project
|
112
|
+
|
113
|
+
If you have an idea you'd like to contribute please log an issue.
|
114
|
+
|
115
|
+
All contributions should be submitted via a pull request.
|
116
|
+
|
117
|
+
## License
|
118
|
+
|
119
|
+
THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
|
120
|
+
|
121
|
+
http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3
|
122
|
+
|
123
|
+
The following attribution statement MUST be cited in your products and applications when using this information.
|
124
|
+
|
125
|
+
> Contains public sector information licensed under the Open Government license v3
|
126
|
+
|
127
|
+
### About the license
|
128
|
+
|
129
|
+
The Open Government Licence (OGL) was developed by the Controller of Her Majesty's Stationery Office (HMSO) to enable information providers in the public sector to license the use and re-use of their information under a common open licence.
|
130
|
+
|
131
|
+
It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require "bundler/setup"
|
4
|
+
rescue LoadError
|
5
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
6
|
+
end
|
7
|
+
|
8
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
9
|
+
load "rails/tasks/engine.rake"
|
10
|
+
|
11
|
+
Bundler::GemHelper.install_tasks
|
12
|
+
|
13
|
+
Dir[File.join(File.dirname(__FILE__), "tasks/**/*.rake")].each {|f| load f }
|
14
|
+
|
15
|
+
require "rspec/core"
|
16
|
+
require "rspec/core/rake_task"
|
17
|
+
|
18
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
19
|
+
RSpec::Core::RakeTask.new(:spec => "app:db:test:prepare")
|
20
|
+
|
21
|
+
task :default => :spec
|
22
|
+
|
23
|
+
require 'github_changelog_generator/task'
|
24
|
+
|
25
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
26
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Journea
|
2
|
+
class EngineController < ::ApplicationController
|
3
|
+
helper Journea::Engine.helpers
|
4
|
+
|
5
|
+
protect_from_forgery with: :exception
|
6
|
+
|
7
|
+
before_action :set_view_paths
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def model
|
12
|
+
::Journea::Journey
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_view_paths
|
16
|
+
prepend_view_path Rails.root.join("app", "views", "steps")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Journea
|
2
|
+
class StepsController < EngineController
|
3
|
+
|
4
|
+
before_action :set_journey
|
5
|
+
|
6
|
+
def edit
|
7
|
+
@step = current_step_class.new(@journea.data_for_form(current_step_class.new))
|
8
|
+
@step.journey = @journea
|
9
|
+
render template: @step.step_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def update
|
13
|
+
@step = current_step_class.new(form_params)
|
14
|
+
@step.pre_save(form_params)
|
15
|
+
@step.journey = @journea
|
16
|
+
if @journea.save_data(@step)
|
17
|
+
@journea.transition_to_next_step
|
18
|
+
redirect_to edit_journey_step_path(@journea, @journea.state_machine.current_state)
|
19
|
+
else
|
20
|
+
render template: @step.step_name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def set_journey
|
27
|
+
@journea = model.find(params[:journey_id])
|
28
|
+
|
29
|
+
requested_state = params[:id]
|
30
|
+
return unless requested_state != @journea.current_state
|
31
|
+
|
32
|
+
@journea.transition_to!(requested_state)
|
33
|
+
end
|
34
|
+
|
35
|
+
def current_step_class
|
36
|
+
class_name = "#{@journea.current_state}_step".classify
|
37
|
+
begin
|
38
|
+
class_name.constantize
|
39
|
+
rescue NameError
|
40
|
+
# If no custom class is available then use the default
|
41
|
+
klass = Step
|
42
|
+
klass.custom_name = @journea.current_state
|
43
|
+
klass
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def form_params
|
48
|
+
params.fetch(current_step_class.step_name.to_sym, {}).permit(current_step_class.permitted_params)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Journea
|
2
|
+
module FormHelper
|
3
|
+
|
4
|
+
# So that we don't have to put url: on every simple form, override the url
|
5
|
+
# generator
|
6
|
+
def polymorphic_path(*args)
|
7
|
+
if args.present?
|
8
|
+
record = args.first
|
9
|
+
return journey_step_path(@journea, @step.step_name) if record.is_a? Step
|
10
|
+
end
|
11
|
+
super(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def link_to_input_with_error(element, messages)
|
15
|
+
capture do
|
16
|
+
messages.map do |message|
|
17
|
+
concat(content_tag(:li) do
|
18
|
+
link_to message, "##{@step.step_name}_#{element}"
|
19
|
+
end)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Journea
|
2
|
+
class Journey < ActiveRecord::Base
|
3
|
+
|
4
|
+
include Statesman::Adapters::ActiveRecordQueries
|
5
|
+
|
6
|
+
has_many :journea_journey_transitions, class_name: "Journea::JourneyTransition", autosave: false
|
7
|
+
has_many :journea_keyvalues, class_name: "Journea::Keyvalue"
|
8
|
+
|
9
|
+
# State Machine related
|
10
|
+
|
11
|
+
def state_machine
|
12
|
+
@state_machine ||= StateMachine.new(self, transition_class: JourneyTransition)
|
13
|
+
end
|
14
|
+
|
15
|
+
delegate :can_transition_to?,
|
16
|
+
:transition_to!,
|
17
|
+
:transition_to,
|
18
|
+
:current_state,
|
19
|
+
:transition_to_next_step,
|
20
|
+
:previous_step,
|
21
|
+
:in_initial_state?,
|
22
|
+
to: :state_machine
|
23
|
+
|
24
|
+
def self.transition_class
|
25
|
+
Journea::JourneyTransition
|
26
|
+
end
|
27
|
+
private_class_method :transition_class
|
28
|
+
|
29
|
+
# Instance methods
|
30
|
+
|
31
|
+
def save_data(step_object)
|
32
|
+
return false unless step_object.valid?
|
33
|
+
step_object.attributes.each do |k, v|
|
34
|
+
key_value_pair = Keyvalue.find_or_initialize_by(key: k.to_s, journey: self)
|
35
|
+
key_value_pair.value = v
|
36
|
+
key_value_pair.save
|
37
|
+
end
|
38
|
+
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
def data_for_form(step_object)
|
43
|
+
data = Keyvalue.where(key: step_object.attributes.keys, journey: self).map do |kv|
|
44
|
+
[kv.key.to_sym, kv.value]
|
45
|
+
end
|
46
|
+
data.to_h
|
47
|
+
end
|
48
|
+
|
49
|
+
def data
|
50
|
+
Data.new(Keyvalue.where(journey: self))
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Journea
|
2
|
+
class JourneyTransition < ActiveRecord::Base
|
3
|
+
include Statesman::Adapters::ActiveRecordTransition
|
4
|
+
|
5
|
+
belongs_to :journey, inverse_of: :journea_journey_transitions
|
6
|
+
|
7
|
+
after_destroy :update_most_recent, if: :most_recent?
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def update_most_recent
|
12
|
+
last_transition = journey.journey_transitions.order(:sort_key).last
|
13
|
+
return unless last_transition.present?
|
14
|
+
last_transition.update_column(:most_recent, true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
- if @journea.present?
|
2
|
+
- if @journea.previous_step.present?
|
3
|
+
= link_to 'Back', edit_journey_step_path(@journea, @journea.previous_step), class: 'link-back back-link'
|
4
|
+
- elsif @journea.in_initial_state?
|
5
|
+
= link_to 'Back', main_app.root_path, class: 'link-back back-link'
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# Use this setup block to configure all options available in SimpleForm.
|
2
|
+
# rubocop:disable Metrics/BlockLength
|
3
|
+
SimpleForm.setup do |config|
|
4
|
+
# Wrappers are used by the form builder to generate a
|
5
|
+
# complete input. You can remove any component from the
|
6
|
+
# wrapper, change the order or even add your own to the
|
7
|
+
# stack. The options given below are used to wrap the
|
8
|
+
# whole input.
|
9
|
+
config.wrappers :default, class: ["form-group", :input],
|
10
|
+
hint_class: :field_with_hint, error_class: :error do |b|
|
11
|
+
## Extensions enabled by default
|
12
|
+
# Any of these extensions can be disabled for a
|
13
|
+
# given input by passing: `f.input EXTENSION_NAME => false`.
|
14
|
+
# You can make any of these extensions optional by
|
15
|
+
# renaming `b.use` to `b.optional`.
|
16
|
+
|
17
|
+
# Determines whether to use HTML5 (:email, :url, ...)
|
18
|
+
# and required attributes
|
19
|
+
b.use :html5
|
20
|
+
|
21
|
+
# Calculates placeholders automatically from I18n
|
22
|
+
# You can also pass a string as f.input placeholder: "Placeholder"
|
23
|
+
b.use :placeholder
|
24
|
+
|
25
|
+
## Optional extensions
|
26
|
+
# They are disabled unless you pass `f.input EXTENSION_NAME => true`
|
27
|
+
# to the input. If so, they will retrieve the values from the model
|
28
|
+
# if any exists. If you want to enable any of those
|
29
|
+
# extensions by default, you can change `b.optional` to `b.use`.
|
30
|
+
|
31
|
+
# Calculates maxlength from length validations for string inputs
|
32
|
+
b.optional :maxlength
|
33
|
+
|
34
|
+
# Calculates pattern from format validations for string inputs
|
35
|
+
b.optional :pattern
|
36
|
+
|
37
|
+
# Calculates min and max from length validations for numeric inputs
|
38
|
+
b.optional :min_max
|
39
|
+
|
40
|
+
# Calculates readonly automatically from readonly attributes
|
41
|
+
b.optional :readonly
|
42
|
+
|
43
|
+
## Inputs
|
44
|
+
b.use :label, class: "form-label"
|
45
|
+
b.use :hint, wrap_with: { tag: :span, class: "form-hint" }
|
46
|
+
b.use :input, class: "form-control"
|
47
|
+
b.use :error, wrap_with: { tag: :span, class: "error-message" }
|
48
|
+
|
49
|
+
## full_messages_for
|
50
|
+
# If you want to display the full error message for the attribute, you can
|
51
|
+
# use the component :full_error, like:
|
52
|
+
#
|
53
|
+
# b.use :full_error, wrap_with: { tag: :span, class: :error }
|
54
|
+
end
|
55
|
+
|
56
|
+
# The default wrapper to be used by the FormBuilder.
|
57
|
+
config.default_wrapper = :default
|
58
|
+
|
59
|
+
# Define the way to render check boxes / radio buttons with labels.
|
60
|
+
# Defaults to :nested for bootstrap config.
|
61
|
+
# inline: input + label
|
62
|
+
# nested: label > input
|
63
|
+
config.boolean_style = :nested
|
64
|
+
|
65
|
+
# Default class for buttons
|
66
|
+
config.button_class = "button"
|
67
|
+
|
68
|
+
# Method used to tidy up errors. Specify any Rails Array method.
|
69
|
+
# :first lists the first message for each field.
|
70
|
+
# Use :to_sentence to list all errors for each field.
|
71
|
+
# config.error_method = :first
|
72
|
+
|
73
|
+
# Default tag used for error notification helper.
|
74
|
+
config.error_notification_tag = :div
|
75
|
+
|
76
|
+
# CSS class to add for error notification helper.
|
77
|
+
config.error_notification_class = "error_notification"
|
78
|
+
|
79
|
+
# ID to add for error notification helper.
|
80
|
+
# config.error_notification_id = nil
|
81
|
+
|
82
|
+
# Series of attempts to detect a default label method for collection.
|
83
|
+
# config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
|
84
|
+
|
85
|
+
# Series of attempts to detect a default value method for collection.
|
86
|
+
# config.collection_value_methods = [ :id, :to_s ]
|
87
|
+
|
88
|
+
# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
|
89
|
+
# config.collection_wrapper_tag = :fieldset
|
90
|
+
|
91
|
+
config.wrappers :vertical_radio_and_checkboxes, tag: "div", class: "form-group", error_class: "error" do |b|
|
92
|
+
b.use :error, wrap_with: { tag: "span", class: "error-message" }
|
93
|
+
b.use :input
|
94
|
+
end
|
95
|
+
|
96
|
+
# You can define the class to use on all collection wrappers. Defaulting to none.
|
97
|
+
# config.collection_wrapper_class = nil
|
98
|
+
|
99
|
+
# You can wrap each item in a collection of radio/check boxes with a tag,
|
100
|
+
# defaulting to :span.
|
101
|
+
# config.item_wrapper_tag = :span
|
102
|
+
|
103
|
+
# You can define a class to use in all item wrappers. Defaulting to none.
|
104
|
+
# config.item_wrapper_class = nil
|
105
|
+
|
106
|
+
# How the label text should be generated altogether with the required text.
|
107
|
+
config.label_text = ->(label, _required, _explicit_label) { label }
|
108
|
+
|
109
|
+
# You can define the class to use on all labels. Default is nil.
|
110
|
+
# config.label_class = nil
|
111
|
+
|
112
|
+
# You can define the default class to be used on forms. Can be overriden
|
113
|
+
# with `html: { :class }`. Defaulting to none.
|
114
|
+
# config.default_form_class = nil
|
115
|
+
|
116
|
+
# You can define which elements should obtain additional classes
|
117
|
+
# config.generate_additional_classes_for = [:wrapper, :label, :input]
|
118
|
+
|
119
|
+
# Whether attributes are required by default (or not). Default is true.
|
120
|
+
# config.required_by_default = true
|
121
|
+
|
122
|
+
# Tell browsers whether to use the native HTML5 validations (novalidate form option).
|
123
|
+
# These validations are enabled in SimpleForm's internal config but disabled by default
|
124
|
+
# in this configuration, which is recommended due to some quirks from different browsers.
|
125
|
+
# To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
|
126
|
+
# change this configuration to true.
|
127
|
+
config.browser_validations = false
|
128
|
+
|
129
|
+
# Collection of methods to detect if a file type was given.
|
130
|
+
# config.file_methods = [ :mounted_as, :file?, :public_filename ]
|
131
|
+
|
132
|
+
# Custom mappings for input types. This should be a hash containing a regexp
|
133
|
+
# to match as key, and the input type that will be used when the field name
|
134
|
+
# matches the regexp as value.
|
135
|
+
# config.input_mappings = { /count/ => :integer }
|
136
|
+
|
137
|
+
# Custom wrappers for input types. This should be a hash containing an input
|
138
|
+
# type as key and the wrapper that will be used for all inputs with specified type.
|
139
|
+
# config.wrapper_mappings = { string: :prepend }
|
140
|
+
|
141
|
+
# Namespaces where SimpleForm should look for custom input classes that
|
142
|
+
# override default inputs.
|
143
|
+
# config.custom_inputs_namespaces << "CustomInputs"
|
144
|
+
|
145
|
+
# Default priority for time_zone inputs.
|
146
|
+
# config.time_zone_priority = nil
|
147
|
+
|
148
|
+
# Default priority for country inputs.
|
149
|
+
# config.country_priority = nil
|
150
|
+
|
151
|
+
# When false, do not use translations for labels.
|
152
|
+
# config.translate_labels = true
|
153
|
+
|
154
|
+
# Automatically discover new inputs in Rails' autoload path.
|
155
|
+
# config.inputs_discovery = true
|
156
|
+
|
157
|
+
# Cache SimpleForm inputs discovery
|
158
|
+
# config.cache_discovery = !Rails.env.development?
|
159
|
+
|
160
|
+
# Default class for inputs
|
161
|
+
# config.input_class = nil
|
162
|
+
|
163
|
+
# Define the default class of the input wrapper of the boolean input.
|
164
|
+
config.boolean_label_class = "checkbox"
|
165
|
+
|
166
|
+
# Defines if the default input wrapper class should be included in radio
|
167
|
+
# collection wrappers.
|
168
|
+
# config.include_default_input_wrapper_class = true
|
169
|
+
|
170
|
+
# Defines which i18n scope will be used in Simple Form.
|
171
|
+
# config.i18n_scope = 'simple_form'
|
172
|
+
|
173
|
+
config.wrapper_mappings = {
|
174
|
+
radio_buttons: :vertical_radio_and_checkboxes,
|
175
|
+
check_boxes: :vertical_radio_and_checkboxes,
|
176
|
+
boolean: :radio
|
177
|
+
}
|
178
|
+
end
|
179
|
+
# rubocop:enable Metrics/BlockLength
|