journea 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +8 -0
  3. data/README.md +131 -0
  4. data/Rakefile +26 -0
  5. data/app/controllers/journea/engine_controller.rb +19 -0
  6. data/app/controllers/journea/journeys_controller.rb +10 -0
  7. data/app/controllers/journea/steps_controller.rb +52 -0
  8. data/app/helpers/journea/form_helper.rb +25 -0
  9. data/app/models/journea/journey.rb +54 -0
  10. data/app/models/journea/journey_transition.rb +17 -0
  11. data/app/models/journea/keyvalue.rb +5 -0
  12. data/app/views/application/_back_link.html.haml +5 -0
  13. data/config/initializers/simple_form.rb +179 -0
  14. data/config/locales/simple_form.en.yml +31 -0
  15. data/config/routes.rb +5 -0
  16. data/db/migrate/20161201153630_create_journey_transitions.rb +22 -0
  17. data/db/migrate/20161201162349_create_journeys_table.rb +10 -0
  18. data/db/migrate/20161202162350_create_keyvalues_table.rb +11 -0
  19. data/lib/generators/journea/install_generator.rb +76 -0
  20. data/lib/generators/journea/templates/assets/application.js +23 -0
  21. data/lib/generators/journea/templates/assets/application.scss +49 -0
  22. data/lib/generators/journea/templates/config/initializers/journea.rb +23 -0
  23. data/lib/generators/journea/templates/config/initializers/journea2.rb +24 -0
  24. data/lib/generators/journea/templates/controllers/pages_controller.rb.example +2 -0
  25. data/lib/generators/journea/templates/views/application.html.haml +20 -0
  26. data/lib/generators/journea/templates/views/pages/start.html.haml.example +12 -0
  27. data/lib/generators/journea/templates/views/shared/error_messages.html.haml.example +7 -0
  28. data/lib/generators/journea/templates/views/steps/step.html.haml.example +8 -0
  29. data/lib/journea.rb +25 -0
  30. data/lib/journea/data.rb +20 -0
  31. data/lib/journea/engine.rb +27 -0
  32. data/lib/journea/state_machine.rb +40 -0
  33. data/lib/journea/step.rb +32 -0
  34. data/lib/journea/version.rb +3 -0
  35. data/lib/simple_form_object.rb +146 -0
  36. data/lib/tasks/journea_tasks.rake +4 -0
  37. data/lib/templates/erb/scaffold/_form.html.erb +13 -0
  38. data/spec/dummy/Rakefile +6 -0
  39. data/spec/dummy/app/assets/config/manifest.js +5 -0
  40. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  41. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  42. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  43. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  44. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  45. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  46. data/spec/dummy/app/controllers/pages_controller.rb +4 -0
  47. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  48. data/spec/dummy/app/jobs/application_job.rb +2 -0
  49. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  50. data/spec/dummy/app/models/application_record.rb +3 -0
  51. data/spec/dummy/app/steps/address_step.rb +4 -0
  52. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  53. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  54. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  55. data/spec/dummy/app/views/pages/start.html.erb +1 -0
  56. data/spec/dummy/app/views/steps/address.html.erb +5 -0
  57. data/spec/dummy/app/views/steps/name.html.erb +5 -0
  58. data/spec/dummy/app/views/steps/phone_number.html.erb +0 -0
  59. data/spec/dummy/bin/bundle +3 -0
  60. data/spec/dummy/bin/rails +4 -0
  61. data/spec/dummy/bin/rake +4 -0
  62. data/spec/dummy/bin/setup +34 -0
  63. data/spec/dummy/bin/update +29 -0
  64. data/spec/dummy/config.ru +5 -0
  65. data/spec/dummy/config/application.rb +14 -0
  66. data/spec/dummy/config/boot.rb +5 -0
  67. data/spec/dummy/config/cable.yml +9 -0
  68. data/spec/dummy/config/database.yml +25 -0
  69. data/spec/dummy/config/environment.rb +5 -0
  70. data/spec/dummy/config/environments/development.rb +54 -0
  71. data/spec/dummy/config/environments/production.rb +86 -0
  72. data/spec/dummy/config/environments/test.rb +42 -0
  73. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  74. data/spec/dummy/config/initializers/assets.rb +11 -0
  75. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  76. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  77. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  78. data/spec/dummy/config/initializers/inflections.rb +16 -0
  79. data/spec/dummy/config/initializers/journea.rb +8 -0
  80. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  81. data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
  82. data/spec/dummy/config/initializers/session_store.rb +3 -0
  83. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  84. data/spec/dummy/config/locales/en.yml +23 -0
  85. data/spec/dummy/config/puma.rb +47 -0
  86. data/spec/dummy/config/routes.rb +4 -0
  87. data/spec/dummy/config/secrets.yml +22 -0
  88. data/spec/dummy/config/spring.rb +6 -0
  89. data/spec/dummy/db/development.sqlite3 +0 -0
  90. data/spec/dummy/db/schema.rb +42 -0
  91. data/spec/dummy/db/test.sqlite3 +0 -0
  92. data/spec/dummy/log/development.log +57 -0
  93. data/spec/dummy/log/test.log +448 -0
  94. data/spec/dummy/public/404.html +67 -0
  95. data/spec/dummy/public/422.html +67 -0
  96. data/spec/dummy/public/500.html +66 -0
  97. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  98. data/spec/dummy/public/apple-touch-icon.png +0 -0
  99. data/spec/dummy/public/favicon.ico +0 -0
  100. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/EA/EAR2KaBsPQau6HwaTGrxV7EGMwAWyS-4C8pGVDU1Z-Q.cache +1 -0
  101. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/JZ/JZuPFgM2mLQgAHB-r7Pt_TdGW3DRWPrplT7xPjnCJSE.cache +1 -0
  102. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LT/LTt1oE1gi9m65YRwUp78DuufkCOfi3sa3Qa05_ykADk.cache +1 -0
  103. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Lj/LjRKOqtrClPtb97phuIWI7HHA8-p5J5nKHVE_zEycxo.cache +1 -0
  104. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QM/QMxUWUtpFaqwG3RI9t3m38QtFAOvHpiY3LphKJiVRTc.cache +1 -0
  105. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/St/StFuOi5bd69ceiqz2D6EOCmRzHgwY0IxERsMfiCneGM.cache +1 -0
  106. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Vj/VjCUmI9pp5eD8BlYATbwJ4ZOk0438rwvtDrsttyWbfQ.cache +0 -0
  107. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Wl/WlLcUIADXcUxaOt8Gq59uQbO0mquikyz7jxiJjXjhaI.cache +1 -0
  108. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/YH/YHo__TrFq5y8rpx49T8d8ecyvMLbHFbnhz7IBV7pM98.cache +1 -0
  109. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Zu/ZuLXgeX6x_Dx8sCUbzuTtWu42HzQXWe7eooTgsonTnc.cache +0 -0
  110. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/aG/aG1tp1pv4kBiSKx9ixZH5xiRXH-rGa0Hi6sdl4SHw6g.cache +3 -0
  111. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/aw/awTDtuorxLsRLIGEYCefR-PTN7yptoaGRLEk13vHVLA.cache +1 -0
  112. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/b_/b_Itlk9QZZd7Rvf8kcA4yLP1R5Acu7jB-m1xQiSU0qE.cache +2 -0
  113. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cW/cWHxYOqms7abJ-dzXyrn2G7nadJicU5kkC8SduS06yc.cache +0 -0
  114. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cb/cbX7RFavWZoWojlrsXhsy4FN46UOfMwZYStkLHT5HJw.cache +1 -0
  115. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/eY/eYTHvo0Wl2TD2vipDcJ966HHXGrA4ZlJaiA2DnftKhM.cache +1 -0
  116. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/f4/f4CpFuYmsdh1EvlFVjsl1WmM2QA9_z9AuOebEOw4mts.cache +0 -0
  117. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gH/gHSjqTBRSW22rP9mSj8XW6huEXKpcIOehvF-2fvuShQ.cache +1 -0
  118. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m0/m0smDeM83DcmOVpX9zos6AIX40E9Tf2j26tyvKFgMwc.cache +1 -0
  119. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mW/mWrwQwWUQpAlMCLQ8dGv5VkAXd-TxvAtB5WPg9l09-A.cache +1 -0
  120. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mX/mX1nlsL_SWOB4y22W5FheRX0YEONKyOY7xUeIvRiHco.cache +2 -0
  121. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/n_/n_xYqQYhwEMQknb3jFQnjlxxBE9TzMNHCdJ-bEyZFIw.cache +2 -0
  122. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/nx/nxTv3sKVUQZADJyM3dPaVmUA78MIsMLD_K279yN_GsI.cache +2 -0
  123. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/oA/oAtzk5ZeF7lWCwNufspgWqtv_dQN_n5GumFNB4ScfBE.cache +2 -0
  124. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/rA/rACdJeX3jZNkhx4awGhdZeMdOfmARubkoVKVAZdwYog.cache +0 -0
  125. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sC/sCEBZXwTjRpEzThf7YHzHNfkAupMVOx_Ko7WNMAFHS0.cache +0 -0
  126. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/x7/x7PYh8DJvPykcEqpVab2vcY9-GFz-3cqtoMlRAu94Uc.cache +2 -0
  127. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/yT/yTOf3QInGfDlRZlwZNDBLlbma19FQRHM035AKRxcRyw.cache +0 -0
  128. data/spec/features/journey_spec.rb +9 -0
  129. data/spec/lib/simple_form_object/attribute_spec.rb +74 -0
  130. data/spec/lib/simple_form_object/delegation_spec.rb +50 -0
  131. data/spec/lib/simple_form_object/model_spec.rb +90 -0
  132. data/spec/lib/steps_spec.rb +0 -0
  133. data/spec/requests/journeys_spec.rb +6 -0
  134. data/spec/spec_helper.rb +44 -0
  135. metadata +449 -0
@@ -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.
@@ -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.
@@ -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,10 @@
1
+ module Journea
2
+ class JourneysController < EngineController
3
+
4
+ def create
5
+ journey = model.create
6
+ redirect_to edit_journey_step_path(journey, journey.state_machine.current_state)
7
+ end
8
+
9
+ end
10
+ 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
+ module Journea
2
+ class Keyvalue < ActiveRecord::Base
3
+ belongs_to :journey
4
+ end
5
+ 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