markup_attributes 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +100 -0
  4. data/Rakefile +27 -0
  5. data/app/helpers/markup_attributes_helper.rb +66 -0
  6. data/lib/markup_attributes/engine.rb +5 -0
  7. data/lib/markup_attributes/version.rb +3 -0
  8. data/lib/markup_attributes.rb +137 -0
  9. data/lib/tasks/markup_attributes_tasks.rake +4 -0
  10. data/spec/dummy/Rakefile +6 -0
  11. data/spec/dummy/app/assets/config/manifest.js +2 -0
  12. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  13. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  14. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  15. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  16. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  17. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  18. data/spec/dummy/app/jobs/application_job.rb +2 -0
  19. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  20. data/spec/dummy/app/models/application_record.rb +3 -0
  21. data/spec/dummy/app/models/basic_model.rb +3 -0
  22. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  23. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  24. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  25. data/spec/dummy/bin/bundle +3 -0
  26. data/spec/dummy/bin/rails +4 -0
  27. data/spec/dummy/bin/rake +4 -0
  28. data/spec/dummy/bin/setup +33 -0
  29. data/spec/dummy/bin/update +28 -0
  30. data/spec/dummy/config/application.rb +29 -0
  31. data/spec/dummy/config/boot.rb +5 -0
  32. data/spec/dummy/config/cable.yml +10 -0
  33. data/spec/dummy/config/database.yml +14 -0
  34. data/spec/dummy/config/environment.rb +5 -0
  35. data/spec/dummy/config/environments/development.rb +46 -0
  36. data/spec/dummy/config/environments/production.rb +71 -0
  37. data/spec/dummy/config/environments/test.rb +36 -0
  38. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  39. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  40. data/spec/dummy/config/initializers/content_security_policy.rb +25 -0
  41. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  42. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  43. data/spec/dummy/config/initializers/inflections.rb +16 -0
  44. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  45. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  46. data/spec/dummy/config/locales/en.yml +33 -0
  47. data/spec/dummy/config/puma.rb +34 -0
  48. data/spec/dummy/config/routes.rb +3 -0
  49. data/spec/dummy/config/spring.rb +6 -0
  50. data/spec/dummy/config/storage.yml +34 -0
  51. data/spec/dummy/config.ru +5 -0
  52. data/spec/dummy/db/dummy_development.sqlite3 +0 -0
  53. data/spec/dummy/db/dummy_test.sqlite3 +0 -0
  54. data/spec/dummy/db/migrate/20190131160549_create_basic_models.rb +10 -0
  55. data/spec/dummy/db/migrate/20190131173158_translation_table_for_basic_model.rb +13 -0
  56. data/spec/dummy/db/migrate/20190201155355_add_second_attribute_to_basic_models.rb +5 -0
  57. data/spec/dummy/db/schema.rb +33 -0
  58. data/spec/dummy/log/development.log +460 -0
  59. data/spec/dummy/log/test.log +11533 -0
  60. data/spec/dummy/public/404.html +67 -0
  61. data/spec/dummy/public/422.html +67 -0
  62. data/spec/dummy/public/500.html +66 -0
  63. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  64. data/spec/dummy/public/apple-touch-icon.png +0 -0
  65. data/spec/dummy/public/favicon.ico +0 -0
  66. data/spec/helpers/markup_attributes_helper_spec.rb +170 -0
  67. data/spec/rails_helper.rb +62 -0
  68. data/spec/spec_helper.rb +96 -0
  69. data/spec/support/html_examples.rb +26 -0
  70. data/spec/support/matchers.rb +17 -0
  71. data/spec/support/textile_examples.rb +50 -0
  72. metadata +288 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 97c6b8cec1b64b794fac504e4893679db9449395
4
+ data.tar.gz: 20456a12c564af69e167736e4ffcf92422995b01
5
+ SHA512:
6
+ metadata.gz: 654d8ed332adf3308ae8905defccaa7f7eb3f12d854bb1650f01af28c3c31c6c71aeb308cdaf61148d0b64623e0dba5551ef127285c2e6f9db4145633fd2f699
7
+ data.tar.gz: 732047395d4b1d68e81422482dcb235c396865441be46157d1073b4c279d953552f9651dde7b8a7f527fc828f494d80e5eb8bf0f4d1cb5f9499b69690159c425
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2019 James Adam
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # MarkupAttributes
2
+ A simple Rails engine for cleanly handling Textile/Markdown markup in ActiveRecord attributes.
3
+
4
+ Using this engine, we can define a particular attribute as containing markup, with constraints around
5
+ which markup rules and tags we want to support, and then render that attribute value to HTML
6
+ consistently throughout the rest of the application.
7
+
8
+ Rather than adding any HTML generation into the model itself, this works by attaching metadata
9
+ to the model, which can then be consumed by a helper when the attribute is used in views.
10
+
11
+ In the future, this will expand to also handle Markdown, Github-Flavoured Markdown and potentially
12
+ any other markup language; the underlying mechanism is markup-agnostic, and others can easily
13
+ be added.
14
+
15
+ ## Usage
16
+ Once you've added this gem to your application, you can enable it on a per-model basis by
17
+ extending the model class with the {#MarkupAttributes} module, and then declaring one or more
18
+ attributes as having textile:
19
+
20
+ class Post < ApplicationRecord
21
+ extend MarkupAttributes
22
+
23
+ textile_attribute :title, :description
24
+ end
25
+
26
+ You can then deal with the model as with any other ActiveRecord subclass; the attributes
27
+ can be treated as simple strings:
28
+
29
+ post = Post.create(title: 'My _cool_ post', description: 'A post about *stuff*')
30
+ post.title # => 'My _cool_ post'
31
+ post.description # => 'A post about *stuff*'
32
+
33
+ When you want to render the markup in a view, use the `render_markup` helper method:
34
+
35
+ <h1><%= render_markup post.title %></h1>
36
+ <p><%= render_markup post.description %></p>
37
+
38
+ which will produce the HTML
39
+
40
+ <h1>My <em>cool</em> post</h1>
41
+ <p>A post about <strong>stuff</strong></p>
42
+
43
+
44
+ ### Markup constraints
45
+
46
+ The main benefit of this gem is that it allows you to define _constraints_ about what markup
47
+ an attribute should support in a single place, and have those rules be applied consistently
48
+ wherever the content is rendered. We do this using the `:allow` and `:deny` options to
49
+ `textile_attribute`.
50
+
51
+ class Post < ApplicationRecord
52
+ extend MarkupAttributes
53
+
54
+ textile_attribute :title, allow: :emphasis
55
+ end
56
+
57
+ If any `:allow` options are set, anything missing from that option is assumed to be denied, and
58
+ will be removed from the rendered markup. So, anywhere we try to render the title markup now,
59
+ these rules will be respected:
60
+
61
+ <% post = Post.new(title: '"Link":http://example.com this _up_') %>
62
+ <%= render_markup post.title %>
63
+
64
+ produces
65
+
66
+ Link this <em>up</em>
67
+
68
+ Because we didn't allow links, that aspect of the markup is removed.
69
+
70
+ We can include multiple allowed markup types:
71
+
72
+ textile_attribute :title, allow: [:emphasis, :links, :images]
73
+
74
+ or, we can allow all markup and then explicitly deny certain types:
75
+
76
+ textile_attribute :title, deny: :images
77
+
78
+
79
+ ## Installation
80
+ Add this line to your application's Gemfile:
81
+
82
+ ```ruby
83
+ gem 'markup_attributes'
84
+ ```
85
+
86
+ And then execute:
87
+ ```bash
88
+ $ bundle
89
+ ```
90
+
91
+ Or install it yourself as:
92
+ ```bash
93
+ $ gem install markup_attributes
94
+ ```
95
+
96
+ ## Contributing
97
+ Contribution directions go here.
98
+
99
+ ## License
100
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'yard'
8
+ YARD::Rake::YardocTask.new(:doc) do |t|
9
+ t.files = ['app/**/*.rb', 'lib/**/*.rb', '-', 'README.md']
10
+ t.options = ['--no-private']
11
+ end
12
+
13
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
14
+ load 'rails/tasks/engine.rake'
15
+
16
+ load 'rails/tasks/statistics.rake'
17
+
18
+ require 'bundler/gem_tasks'
19
+
20
+ if defined? RSpec
21
+ task(:spec).clear
22
+ RSpec::Core::RakeTask.new(:spec) do |t|
23
+ t.verbose = false
24
+ end
25
+ end
26
+
27
+ task default: :spec
@@ -0,0 +1,66 @@
1
+ # The top-level Rails helper which enables consistent rendering of markup attributes.
2
+ #
3
+ # Rails will make this automatically available in your views; you may need to explicitly
4
+ # include it in other places (like serializers).
5
+ #
6
+ # This helper exposes a single method: +render_markup+
7
+ module MarkupAttributesHelper
8
+
9
+ # Given an attribute, returned an HTML-safe, rendered version of the content
10
+ # in that attribute, rendered according to the markup options defined in the model.
11
+ #
12
+ # If the passed attribute has not been configured as a markup attribute, it will be
13
+ # returned without performing any rendering at all. Th ft ft
14
+ #
15
+ # @param markup_attribute [String] the attribute to render. If this is an attribute that
16
+ # has not been configured as a markup attribute, it will be returned without any rendering.
17
+ # @example rendering an attribute from a model
18
+ # # Given this model exists somewhere, with `title` as a markup attribute:
19
+ # # post = Post.new(title: '"This":http://example.com is _great_')
20
+ #
21
+ # render_markup(post.title) # => '<a href="http://example.com" rel="nofollow">This</a> is <em>great</em>'
22
+ def render_markup(markup_attribute)
23
+ return markup_attribute if markup_attribute.blank?
24
+
25
+ if markup_attribute.respond_to?(:markup_options)
26
+ options = markup_attribute.markup_options
27
+
28
+ html = case options[:markup]
29
+ when :textile
30
+ require 'redcloth'
31
+ RedCloth.new(sanitize(markup_attribute), [:no_span_caps]).to_html
32
+ else
33
+ raise "unknown markup attribute type: #{options[:markup]}"
34
+ end
35
+
36
+ cleaned_html = clean_rendered_markup(html, options)
37
+ cleaned_html.html_safe
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def clean_rendered_markup(html, options)
44
+ cleaned_html = if options[:allow] == [:all]
45
+ denied_tags = tags_from_tag_types(*options[:deny])
46
+ allowed_tags = Rails::Html::WhiteListSanitizer.allowed_tags.reject { |tag| denied_tags.include?(tag.to_s) }
47
+ whitelisted_html = Rails::Html::WhiteListSanitizer.new.sanitize(html, tags: allowed_tags).strip
48
+ whitelisted_html
49
+ else
50
+ allowed_tags = tags_from_tag_types(*options[:allow])
51
+ cleaned_html = Rails::Html::WhiteListSanitizer.new.sanitize(html, tags: allowed_tags).strip
52
+ cleaned_html = Loofah.scrub_fragment(cleaned_html, :nofollow).to_html if options[:allow].include?(:links)
53
+ cleaned_html
54
+ end
55
+
56
+ cleaned_html
57
+ end
58
+
59
+ def tags_from_tag_types(*tag_types)
60
+ tags = []
61
+ tags += %w(i em) if tag_types.include?(:emphasis)
62
+ tags += %w(a) if tag_types.include?(:links)
63
+ tags += %w(img) if tag_types.include?(:images)
64
+ tags
65
+ end
66
+ end
@@ -0,0 +1,5 @@
1
+ module MarkupAttributes
2
+ # @private
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module MarkupAttributes
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,137 @@
1
+ require "markup_attributes/engine"
2
+
3
+ # The main behaviour for defining markup attributes
4
+ #
5
+ # To enable this for your models, either extend it directly into one or more models,
6
+ # or extend it into `ApplicationRecord` to include it everywhere
7
+ #
8
+ # == Markup constraints
9
+ # Markup content typically comes from users of the app, and as with any user-generated
10
+ # content, we probably can't allow them to insert any old HTML into our rendered pages.
11
+ #
12
+ # The main benefit of this approach is that it allows us to declare constraints on
13
+ # the types of markup we want to deal with in a single place, but without coupling
14
+ # rendering logic into the model itself.
15
+ #
16
+ # Those constraints are grouped into certain types of elements:
17
+ #
18
+ # Emphasis (:emphasis):: allow `i` and `em` tags.
19
+ # Links (:links):: allow `a` tags, but mark them as `nofollow` so that they are not useful
20
+ # for spammers.
21
+ # Images (:images):: allow `img` tags.
22
+ #
23
+ # == Automatic sanitisation
24
+ #
25
+ # All the HTML generated is automatically run through Rails' own sanitisation mechanism,
26
+ # which means that things like `<script>alert();</script>` will automatically either
27
+ # be sanitised into a non-running piece of content, or entirely removed, depending on
28
+ # the options given.
29
+ #
30
+ # @example a simple model declaring textile attributes
31
+ # class Post < ApplicationRecord
32
+ # extend MarkupAttributes
33
+ #
34
+ # textile_attribute :title, :description, allow: [:emphasis, :images]
35
+ #
36
+ # # ...
37
+ # end
38
+ module MarkupAttributes
39
+ # A subclass of string which the attributes are cast into by ActiveRecord
40
+ # @private
41
+ class MarkupString < String
42
+ attr_accessor :markup_options
43
+ end
44
+
45
+ # The type used by ActiveRecord's attributes API
46
+ # @private
47
+ class MarkupType < ActiveRecord::Type::String
48
+ def self.inspect
49
+ "<MarkupType [#{markup_options}]>"
50
+ end
51
+
52
+ def markup_options
53
+ self.class.markup_options
54
+ end
55
+
56
+ def cast(value)
57
+ if value.is_a?(String) || value.is_a?(MarkupString)
58
+ MarkupString.new(value).tap { |s| s.markup_options = self.markup_options }
59
+ else
60
+ super
61
+ end
62
+ end
63
+ end
64
+
65
+ ActiveRecord::Type.register(:markup, MarkupType)
66
+
67
+ # Declare one or more attributes as containing Textile markup.
68
+ # @param (see #markup_attribute)
69
+ # @example An attribute which only supports Textile emphasis and links
70
+ # textile_attribute :title, allow: [:emphasis, :links]
71
+ # @example An attribute which supports everything except images
72
+ # textile_attribute :title, deny: [:images]
73
+ def textile_attribute(*attribute_names, **options)
74
+ markup_attribute(*attribute_names, **options.merge(markup: :textile))
75
+ end
76
+
77
+ # Declare one or more attributes as containing Markdown markup.
78
+ # @param (see #markup_attribute)
79
+ def markdown_attribute(*attribute_names, **options)
80
+ markup_attribute(*attribute_names, **options.merge(markup: :markdown))
81
+ end
82
+
83
+ # Declare one or more attributes as containing markup content
84
+ #
85
+ # == Markup types
86
+ # The following types can be provided in either the +:allow+ or +:deny+ options:
87
+ # :emphasis:: +i+ and +em+ tags
88
+ # :links:: +a+ tags (will all have +rel=nofollow+ automatically set)
89
+ # :images:: +img+ tags
90
+ #
91
+ # @param attribute_names [Symbol, Array<Symbol>] One or more attribute names to mark as containing markup
92
+ # @param options [Hash<Symbol=>Symbol>, Hash<Symbol=>Array<Symbol>>] Options to be used when rendering this/these attributes
93
+ # @option options [Symbol] :markup The markup engine to use, either +:textile+ or +:markdown+. If you use either of
94
+ # +textile_attribute+ or +markdown_attribute+, wrapper methods, this will be set automatically.
95
+ # @option options [Symbol, Array<Symbol>] :allow Which types of markup to allow (any not included are implicity denied)
96
+ # @option options [Symbol, Array<symbol>] :deny Which types of markup to deny (any not included are implicity allowed)
97
+ def markup_attribute(*attribute_names, **options)
98
+ raise "must define :markup option" unless options[:markup]
99
+ options.deep_symbolize_keys!
100
+ options[:allow] = Array.wrap(options[:allow] || :all).map(&:to_sym)
101
+ options[:deny] = Array.wrap(options[:deny]).map(&:to_sym)
102
+ options.freeze
103
+
104
+ attribute_registry_type = get_type_for(options)
105
+
106
+ attribute_names.each do |attribute_name|
107
+ if respond_to?(:translates?) && translates? && translated_attribute_names.include?(attribute_name)
108
+ translation_class.attribute attribute_name, attribute_registry_type
109
+ else
110
+ attribute attribute_name, attribute_registry_type
111
+ end
112
+ end
113
+ end
114
+
115
+ private
116
+
117
+ MARKUP_TYPES_REGISTRY = {}
118
+
119
+ def get_type_for(options)
120
+ allow_keys = options[:allow].map { |x| "+#{x}" }
121
+ deny_keys = options[:deny].map { |x| "-#{x}" }
122
+ type_key = [options[:markup],(allow_keys + deny_keys).sort.join].join('=>').to_sym
123
+ MARKUP_TYPES_REGISTRY.fetch(type_key) do
124
+ klass = eval <<-TYPE_CLASS
125
+ Class.new(MarkupType) do
126
+ def self.markup_options
127
+ #{options.inspect}
128
+ end
129
+ end
130
+ TYPE_CLASS
131
+ ActiveRecord::Type.register(type_key, klass)
132
+ MARKUP_TYPES_REGISTRY[type_key] = klass
133
+ klass
134
+ end
135
+ type_key
136
+ end
137
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :markup_attributes do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,2 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../stylesheets .css
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require activestorage
15
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationJob < ActiveJob::Base
2
+ end
@@ -0,0 +1,4 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: 'from@example.com'
3
+ layout 'mailer'
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
@@ -0,0 +1,3 @@
1
+ class BasicModel < ApplicationRecord
2
+ extend MarkupAttributes
3
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag 'application', media: 'all' %>
9
+ </head>
10
+
11
+ <body>
12
+ <%= yield %>
13
+ </body>
14
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
+ <style>
6
+ /* Email styles need to be inline */
7
+ </style>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../config/application', __dir__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+ include FileUtils
4
+
5
+ # path to your application root.
6
+ APP_ROOT = File.expand_path('..', __dir__)
7
+
8
+ def system!(*args)
9
+ system(*args) || abort("\n== Command #{args} failed ==")
10
+ end
11
+
12
+ chdir APP_ROOT do
13
+ # This script is a starting point to setup your application.
14
+ # Add necessary setup steps to this file.
15
+
16
+ puts '== Installing dependencies =='
17
+ system! 'gem install bundler --conservative'
18
+ system('bundle check') || system!('bundle install')
19
+
20
+ # puts "\n== Copying sample files =="
21
+ # unless File.exist?('config/database.yml')
22
+ # cp 'config/database.yml.sample', 'config/database.yml'
23
+ # end
24
+
25
+ puts "\n== Preparing database =="
26
+ system! 'bin/rails db:setup'
27
+
28
+ puts "\n== Removing old logs and tempfiles =="
29
+ system! 'bin/rails log:clear tmp:clear'
30
+
31
+ puts "\n== Restarting application server =="
32
+ system! 'bin/rails restart'
33
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+ include FileUtils
4
+
5
+ # path to your application root.
6
+ APP_ROOT = File.expand_path('..', __dir__)
7
+
8
+ def system!(*args)
9
+ system(*args) || abort("\n== Command #{args} failed ==")
10
+ end
11
+
12
+ chdir APP_ROOT do
13
+ # This script is a way to update your development environment automatically.
14
+ # Add necessary update steps to this file.
15
+
16
+ puts '== Installing dependencies =='
17
+ system! 'gem install bundler --conservative'
18
+ system('bundle check') || system!('bundle install')
19
+
20
+ puts "\n== Updating database =="
21
+ system! 'bin/rails db:migrate'
22
+
23
+ puts "\n== Removing old logs and tempfiles =="
24
+ system! 'bin/rails log:clear tmp:clear'
25
+
26
+ puts "\n== Restarting application server =="
27
+ system! 'bin/rails restart'
28
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'boot'
2
+
3
+ require "rails"
4
+ # Pick the frameworks you want:
5
+ require "active_model/railtie"
6
+ require "active_record/railtie"
7
+ require "action_controller/railtie"
8
+ require "action_view/railtie"
9
+
10
+ Bundler.require(*Rails.groups)
11
+ require "markup_attributes"
12
+ require 'globalize'
13
+
14
+
15
+ module Dummy
16
+ class Application < Rails::Application
17
+ # Initialize configuration defaults for originally generated Rails version.
18
+ config.load_defaults 5.2
19
+
20
+ config.i18n.available_locales = ['en-US', 'fr-FR']
21
+ config.i18n.default_locale = 'en-US'
22
+
23
+ # Settings in config/environments/* take precedence over those specified here.
24
+ # Application configuration can go into files in config/initializers
25
+ # -- all .rb files in that directory are automatically loaded after loading
26
+ # the framework and any gems in your application.
27
+ end
28
+ end
29
+
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
@@ -0,0 +1,10 @@
1
+ development:
2
+ adapter: async
3
+
4
+ test:
5
+ adapter: async
6
+
7
+ production:
8
+ adapter: redis
9
+ url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10
+ channel_prefix: dummy_production
@@ -0,0 +1,14 @@
1
+ default: &default
2
+ adapter: sqlite3
3
+ encoding: unicode
4
+ # For details on connection pooling, see Rails configuration guide
5
+ # http://guides.rubyonrails.org/configuring.html#database-pooling
6
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
7
+
8
+ development:
9
+ <<: *default
10
+ database: db/dummy_development.sqlite3
11
+
12
+ test:
13
+ <<: *default
14
+ database: db/dummy_test.sqlite3
@@ -0,0 +1,5 @@
1
+ # Load the Rails application.
2
+ require_relative 'application'
3
+
4
+ # Initialize the Rails application.
5
+ Rails.application.initialize!