minimum_viable_product 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/javascripts/minimum_viable_product/application.js.erb +38 -0
  6. data/app/assets/javascripts/minimum_viable_product/init/controllers.js +23 -0
  7. data/app/assets/stylesheets/minimum_viable_product/application.scss +23 -0
  8. data/app/assets/stylesheets/minimum_viable_product/components/buttons.scss +20 -0
  9. data/app/assets/stylesheets/minimum_viable_product/components/fonts.scss +15 -0
  10. data/app/assets/stylesheets/minimum_viable_product/components/spacing.scss +13 -0
  11. data/app/assets/stylesheets/minimum_viable_product/components/typography.scss +40 -0
  12. data/app/assets/stylesheets/minimum_viable_product/init/_reset.scss +43 -0
  13. data/app/assets/stylesheets/minimum_viable_product/init/layout.scss +42 -0
  14. data/app/assets/stylesheets/minimum_viable_product/layout/basic.scss +6 -0
  15. data/app/assets/stylesheets/minimum_viable_product/layout/carousel.scss +128 -0
  16. data/app/assets/stylesheets/minimum_viable_product/layout/cover.scss +111 -0
  17. data/app/assets/stylesheets/minimum_viable_product/pages/sample.scss +14 -0
  18. data/app/assets/stylesheets/minimum_viable_product/skin/style.scss +8 -0
  19. data/app/controllers/minimum_viable_product/analytics_controller.rb +14 -0
  20. data/app/controllers/minimum_viable_product/concerns/analytics_concern.rb +77 -0
  21. data/app/controllers/minimum_viable_product/concerns/seo_concern.rb +25 -0
  22. data/app/controllers/minimum_viable_product/concerns/session_concern.rb +40 -0
  23. data/app/controllers/minimum_viable_product/controller.rb +11 -0
  24. data/app/controllers/minimum_viable_product/seo_controller.rb +13 -0
  25. data/app/controllers/minimum_viable_product/styleguide_controller.rb +17 -0
  26. data/app/helpers/minimum_viable_product/analytics_helper.rb +4 -0
  27. data/app/helpers/minimum_viable_product/application_helper.rb +15 -0
  28. data/app/helpers/minimum_viable_product/bootstrap_helper.rb +38 -0
  29. data/app/helpers/minimum_viable_product/seo_helper.rb +4 -0
  30. data/app/helpers/minimum_viable_product/styleguide_helper.rb +4 -0
  31. data/app/models/concerns/slugification.rb +16 -0
  32. data/app/views/layouts/minimum_viable_product/_header.html.erb +48 -0
  33. data/app/views/layouts/minimum_viable_product/_instrumentation.html.erb +75 -0
  34. data/app/views/layouts/minimum_viable_product/_meta.html.erb +37 -0
  35. data/app/views/layouts/minimum_viable_product/application.html.erb +24 -0
  36. data/app/views/layouts/minimum_viable_product/basic.html.erb +10 -0
  37. data/app/views/layouts/minimum_viable_product/carousel.html.erb +13 -0
  38. data/app/views/layouts/minimum_viable_product/cover.html.erb +13 -0
  39. data/bin/mvp +68 -0
  40. data/config/initializers/canonical_host.rb +3 -0
  41. data/config/initializers/client_side_validations.rb +20 -0
  42. data/config/initializers/cloudinary.rb +6 -0
  43. data/config/initializers/geocoder.rb +9 -0
  44. data/config/initializers/iteration.rb +33 -0
  45. data/config/initializers/rollbar.rb +59 -0
  46. data/config/initializers/segment.rb +5 -0
  47. data/config/initializers/simple_form.rb +165 -0
  48. data/config/initializers/simple_form_bootstrap.rb +149 -0
  49. data/config/initializers/spoof_ip.rb +33 -0
  50. data/config/initializers/ssl.rb +3 -0
  51. data/config/routes.rb +16 -0
  52. data/lib/minimum_viable_product/engine.rb +20 -0
  53. data/lib/minimum_viable_product/ext/nil.rb +5 -0
  54. data/lib/minimum_viable_product/ext/string.rb +7 -0
  55. data/lib/minimum_viable_product/version.rb +3 -0
  56. data/lib/minimum_viable_product.rb +6 -0
  57. data/lib/tasks/sitemap.rake +42 -0
  58. data/test/dummy/README.rdoc +28 -0
  59. data/test/dummy/Rakefile +6 -0
  60. data/test/dummy/app/assets/javascripts/application.js +13 -0
  61. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  62. data/test/dummy/app/controllers/application_controller.rb +5 -0
  63. data/test/dummy/app/helpers/application_helper.rb +2 -0
  64. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  65. data/test/dummy/bin/bundle +3 -0
  66. data/test/dummy/bin/rails +4 -0
  67. data/test/dummy/bin/rake +4 -0
  68. data/test/dummy/bin/setup +29 -0
  69. data/test/dummy/config/application.rb +26 -0
  70. data/test/dummy/config/boot.rb +5 -0
  71. data/test/dummy/config/database.yml +25 -0
  72. data/test/dummy/config/environment.rb +5 -0
  73. data/test/dummy/config/environments/development.rb +41 -0
  74. data/test/dummy/config/environments/production.rb +79 -0
  75. data/test/dummy/config/environments/test.rb +42 -0
  76. data/test/dummy/config/initializers/assets.rb +11 -0
  77. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  78. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  79. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  80. data/test/dummy/config/initializers/inflections.rb +16 -0
  81. data/test/dummy/config/initializers/mime_types.rb +4 -0
  82. data/test/dummy/config/initializers/session_store.rb +3 -0
  83. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  84. data/test/dummy/config/locales/en.yml +23 -0
  85. data/test/dummy/config/routes.rb +4 -0
  86. data/test/dummy/config/secrets.yml +22 -0
  87. data/test/dummy/config.ru +4 -0
  88. data/test/dummy/public/404.html +67 -0
  89. data/test/dummy/public/422.html +67 -0
  90. data/test/dummy/public/500.html +66 -0
  91. data/test/dummy/public/favicon.ico +0 -0
  92. data/test/integration/navigation_test.rb +8 -0
  93. data/test/minimum_viable_product_test.rb +7 -0
  94. data/test/test_helper.rb +21 -0
  95. metadata +595 -0
@@ -0,0 +1,75 @@
1
+ <% if ENV['ROLLBAR_CLIENT_ACCESS_TOKEN'] %>
2
+ <script>
3
+ var _rollbarConfig = {
4
+ accessToken: '<%= ENV['ROLLBAR_CLIENT_ACCESS_TOKEN'] %>',
5
+ captureUncaught: true,
6
+ captureUnhandledRejections: false,
7
+ payload: {
8
+ environment: "production"
9
+ }
10
+ };
11
+ // Rollbar Snippet
12
+ !function(r){function e(t){if(o[t])return o[t].exports;var n=o[t]={exports:{},id:t,loaded:!1};return r[t].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var o={};return e.m=r,e.c=o,e.p="",e(0)}([function(r,e,o){"use strict";var t=o(1).Rollbar,n=o(2);_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://d37gvrvc0wt4s1.cloudfront.net/js/v1.9/rollbar.min.js";var a=t.init(window,_rollbarConfig),i=n(a,_rollbarConfig);a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,i)},function(r,e){"use strict";function o(r){return function(){try{return r.apply(this,arguments)}catch(e){try{console.error("[Rollbar]: Internal error",e)}catch(o){}}}}function t(r,e,o){window._rollbarWrappedError&&(o[4]||(o[4]=window._rollbarWrappedError),o[5]||(o[5]=window._rollbarWrappedError._rollbarContext),window._rollbarWrappedError=null),r.uncaughtError.apply(r,o),e&&e.apply(window,o)}function n(r){var e=function(){var e=Array.prototype.slice.call(arguments,0);t(r,r._rollbarOldOnError,e)};return e.belongsToShim=!0,e}function a(r){this.shimId=++c,this.notifier=null,this.parentShim=r,this._rollbarOldOnError=null}function i(r){var e=a;return o(function(){if(this.notifier)return this.notifier[r].apply(this.notifier,arguments);var o=this,t="scope"===r;t&&(o=new e(this));var n=Array.prototype.slice.call(arguments,0),a={shim:o,method:r,args:n,ts:new Date};return window._rollbarShimQueue.push(a),t?o:void 0})}function l(r,e){if(e.hasOwnProperty&&e.hasOwnProperty("addEventListener")){var o=e.addEventListener;e.addEventListener=function(e,t,n){o.call(this,e,r.wrap(t),n)};var t=e.removeEventListener;e.removeEventListener=function(r,e,o){t.call(this,r,e&&e._wrapped?e._wrapped:e,o)}}}var c=0;a.init=function(r,e){var t=e.globalAlias||"Rollbar";if("object"==typeof r[t])return r[t];r._rollbarShimQueue=[],r._rollbarWrappedError=null,e=e||{};var i=new a;return o(function(){if(i.configure(e),e.captureUncaught){i._rollbarOldOnError=r.onerror,r.onerror=n(i);var o,a,c="EventTarget,Window,Node,ApplicationCache,AudioTrackList,ChannelMergerNode,CryptoOperation,EventSource,FileReader,HTMLUnknownElement,IDBDatabase,IDBRequest,IDBTransaction,KeyOperation,MediaController,MessagePort,ModalWindow,Notification,SVGElementInstance,Screen,TextTrack,TextTrackCue,TextTrackList,WebSocket,WebSocketWorker,Worker,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload".split(",");for(o=0;o<c.length;++o)a=c[o],r[a]&&r[a].prototype&&l(i,r[a].prototype)}return e.captureUnhandledRejections&&(i._unhandledRejectionHandler=function(r){var e=r.reason,o=r.promise,t=r.detail;!e&&t&&(e=t.reason,o=t.promise),i.unhandledRejection(e,o)},r.addEventListener("unhandledrejection",i._unhandledRejectionHandler)),r[t]=i,i})()},a.prototype.loadFull=function(r,e,t,n,a){var i=function(){var e;if(void 0===r._rollbarPayloadQueue){var o,t,n,i;for(e=new Error("rollbar.js did not load");o=r._rollbarShimQueue.shift();)for(n=o.args,i=0;i<n.length;++i)if(t=n[i],"function"==typeof t){t(e);break}}"function"==typeof a&&a(e)},l=!1,c=e.createElement("script"),d=e.getElementsByTagName("script")[0],p=d.parentNode;c.crossOrigin="",c.src=n.rollbarJsUrl,c.async=!t,c.onload=c.onreadystatechange=o(function(){if(!(l||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)){c.onload=c.onreadystatechange=null;try{p.removeChild(c)}catch(r){}l=!0,i()}}),p.insertBefore(c,d)},a.prototype.wrap=function(r,e){try{var o;if(o="function"==typeof e?e:function(){return e||{}},"function"!=typeof r)return r;if(r._isWrap)return r;if(!r._wrapped){r._wrapped=function(){try{return r.apply(this,arguments)}catch(e){throw e._rollbarContext=o()||{},e._rollbarContext._wrappedSource=r.toString(),window._rollbarWrappedError=e,e}},r._wrapped._isWrap=!0;for(var t in r)r.hasOwnProperty(t)&&(r._wrapped[t]=r[t])}return r._wrapped}catch(n){return r}};for(var d="log,debug,info,warn,warning,error,critical,global,configure,scope,uncaughtError,unhandledRejection".split(","),p=0;p<d.length;++p)a.prototype[d[p]]=i(d[p]);r.exports={Rollbar:a,_rollbarWindowOnError:t}},function(r,e){"use strict";r.exports=function(r,e){return function(o){if(!o&&!window._rollbarInitialized){var t=window.RollbarNotifier,n=e||{},a=n.globalAlias||"Rollbar",i=window.Rollbar.init(n,r);i._processShimQueue(window._rollbarShimQueue||[]),window[a]=i,window._rollbarInitialized=!0,t.processPayloads()}}}}]);
13
+ // End Rollbar Snippet
14
+ </script>
15
+ <% end %>
16
+
17
+ <% unless cookies[MVP::AnalyticsConcern::INVISIBLE_SESSION_COOKIE].to_b == true %>
18
+ <% if ENV['FACEBOOK_TRACKING_ID'] %>
19
+ <script>
20
+ !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
21
+ n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
22
+ n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
23
+ t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
24
+ document,'script','https://connect.facebook.net/en_US/fbevents.js');
25
+
26
+ fbq('init', '<%= ENV['FACEBOOK_TRACKING_ID'] %>');
27
+ fbq('track', "PageView");</script>
28
+ <noscript><img height="1" width="1" style="display:none"
29
+ src="https://www.facebook.com/tr?id=<%= ENV['FACEBOOK_TRACKING_ID'] %>&ev=PageView&noscript=1"
30
+ /></noscript>
31
+ <!-- End Facebook Pixel Code -->
32
+ <% end %>
33
+
34
+ <% if ENV['SEGMENT_WRITE_KEY'] %>
35
+ <script type="text/javascript">
36
+ !function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t){var e=document.createElement("script");e.type="text/javascript";e.async=!0;e.src=("https:"===document.location.protocol?"https://":"http://")+"cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(e,n)};analytics.SNIPPET_VERSION="3.1.0";
37
+ analytics.load('<%= ENV['SEGMENT_WRITE_KEY'] %>');
38
+ <% if current_user %>
39
+ analytics.identify('<%= analytics_id %>', {
40
+ email: '<%= current_user.email %>'
41
+ });
42
+ <% else %>
43
+ analytics.identify('<%= analytics_id %>');
44
+ <% end %>
45
+ analytics.page('<%= controller.controller_path %>.<%= controller.action_name %>', {
46
+ iteration: "<%= MVP::Iteration.version %>"
47
+ });
48
+ }}();
49
+ </script>
50
+ <% end %>
51
+
52
+ <% if ENV['GOOGLE_ANALYTICS_ID'] %>
53
+ <script>
54
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
55
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
56
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
57
+ })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
58
+ ga('create', '<%= ENV['GOOGLE_ANALYTICS_ID'] %>', 'auto');
59
+ ga('send', 'pageview');
60
+ </script>
61
+ <% end %>
62
+
63
+ <% if ENV['HOTJAR_ID'] %>
64
+ <script>
65
+ (function(h,o,t,j,a,r){
66
+ h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
67
+ h._hjSettings={hjid:<%= ENV['HOTJAR_ID'] %>,hjsv:5};
68
+ a=o.getElementsByTagName('head')[0];
69
+ r=o.createElement('script');r.async=1;
70
+ r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
71
+ a.appendChild(r);
72
+ })(window,document,'//static.hotjar.com/c/hotjar-','.js?sv=');
73
+ </script>
74
+ <% end %>
75
+ <% end %>
@@ -0,0 +1,37 @@
1
+ <meta charset=utf-8>
2
+ <meta content="IE=edge" http-equiv=X-UA-Compatible>
3
+ <meta content="width=device-width,initial-scale=1" name=viewport>
4
+ <% if page.description %>
5
+ <meta content="<%= page.description %>" name="description">
6
+ <% end %>
7
+ <% if page.author %>
8
+ <meta content="<%= page.author %>" name="author">
9
+ <% end %>
10
+ <title><%= page.title %></title>
11
+
12
+ <% if page.canonical_url %>
13
+ <link rel="canonical" href="<%= page.canonical_url %>" />
14
+ <% end %>
15
+
16
+ <% if page.noindex %>
17
+ <meta name="robots" content="noindex">
18
+ <% end %>
19
+
20
+ <% if page.og_url %>
21
+ <meta property="og:url" content="<%= page.og_url %>" />
22
+ <% end %>
23
+ <% if page.og_type %>
24
+ <meta property="og:type" content="<%= page.og_type %>" />
25
+ <% end %>
26
+ <% if page.og_title || page.title %>
27
+ <meta property="og:title" content="<%= page.og_title || page.title %>" />
28
+ <% end %>
29
+ <% if page.og_description || page.description %>
30
+ <meta property="og:description" content="<%= page.og_description || page.description %>" />
31
+ <% end %>
32
+ <% if page.og_image %>
33
+ <meta property="og:image" content="<%= page.og_image %>" />
34
+ <% end %>
35
+ <% if page.twitter_card %>
36
+ <meta name="twitter:card" content="<%= page.twitter_card %>" />
37
+ <% end %>
@@ -0,0 +1,24 @@
1
+ <!DOCTYPE HTML>
2
+ <html lang='en'>
3
+ <head>
4
+ <%= render('layouts/minimum_viable_product/meta').gsub(/\n/,'').html_safe %>
5
+
6
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
7
+ <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700|Roboto+Slab|Pacifico' rel='stylesheet' type='text/css'>
8
+
9
+ <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
10
+ <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]-->
11
+
12
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
13
+ <%= csrf_meta_tags %>
14
+
15
+ <%= render 'layouts/minimum_viable_product/instrumentation' %>
16
+ </head>
17
+ <body id="<%= body_id %>" class="<%= body_classes %>" data-controller="<%= controller.controller_path %>" data-action="<%= controller.action_name %>" data-iteration="<%= MVP::Iteration.version %>">
18
+ <% if content_for? :body %>
19
+ <%= yield :body %>
20
+ <% else %>
21
+ <%= yield %>
22
+ <% end %>
23
+ </body>
24
+ </html>
@@ -0,0 +1,10 @@
1
+ <% page.classes = "body-basic" %>
2
+
3
+ <%- content_for :body do %>
4
+ <div class="container">
5
+ <%= render 'layouts/minimum_viable_product/header' %>
6
+ <%= yield %>
7
+ </div>
8
+ <% end %>
9
+
10
+ <%= render template: "layouts/minimum_viable_product/application" %>
@@ -0,0 +1,13 @@
1
+ <% page.classes = "body-carousel" %>
2
+
3
+ <%- content_for :body do %>
4
+ <div class="container">
5
+ <%= render 'layouts/minimum_viable_product/header' %>
6
+ </div>
7
+ <%= yield :carousel %>
8
+ <div class="container">
9
+ <%= yield %>
10
+ </div>
11
+ <% end %>
12
+
13
+ <%= render template: "layouts/minimum_viable_product/application" %>
@@ -0,0 +1,13 @@
1
+ <% page.classes = "body-cover" %>
2
+
3
+ <%- content_for :body do %>
4
+ <div class="site-wrapper">
5
+ <div class="site-wrapper-inner">
6
+ <div class="cover-container">
7
+ <%= yield %>
8
+ </div>
9
+ </div>
10
+ </div>
11
+ <% end %>
12
+
13
+ <%= render template: "layouts/minimum_viable_product/application" %>
data/bin/mvp ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ command = ARGV[0]
4
+
5
+ error(%%
6
+ No command specified, please use one of the following
7
+ new: start a new project
8
+ update: update mvp inside current project
9
+ %) unless command
10
+
11
+ case command.downcase
12
+ when 'new'
13
+ project = if ARGV[1]
14
+ ARGV[1]
15
+ else
16
+ $stdin.reopen(File.open("/dev/tty", "r"))
17
+ print "Project name? "
18
+ STDIN.gets.chomp
19
+ end
20
+
21
+ error('Must specify a project name') if project == ""
22
+
23
+ slug = slugify(project)
24
+
25
+ puts
26
+ puts "\n== Cloning Base Project =="
27
+ run "git clone git@github.com:ian/mvp_rails.git #{slug}"
28
+
29
+ puts
30
+ puts "\n== Initializing Project =="
31
+ files = Dir.glob("#{slug}/**/*").select { |f| File.file?(f) }
32
+ files.each do |file_name|
33
+ text = File.read(file_name)
34
+ new_contents = text.gsub(/__PROJECT_NAME__/, project)
35
+ .gsub(/__PROJECT_NAME_SLUG__/, slug)
36
+
37
+ File.open(file_name, "w") {|file| file.puts new_contents }
38
+ end
39
+ run "cd #{slug} && rm -rf .git && git init"
40
+
41
+ run "cd #{slug}; bin/setup", "\n== Project Setup"
42
+
43
+ when 'update'
44
+ puts "TBD"
45
+ end
46
+
47
+ BEGIN {
48
+ def slugify(name)
49
+ slug = name.gsub(/'/, '').gsub(/[^a-z0-9]+/, '_')
50
+ slug.chop! if slug[-1] == '-'
51
+ slug
52
+ end
53
+
54
+ def error(message)
55
+ puts
56
+ puts "Error: #{message}"
57
+ exit 1
58
+ end
59
+
60
+ def run(cmd, message=nil)
61
+ if message
62
+ puts
63
+ puts message
64
+ end
65
+
66
+ system cmd
67
+ end
68
+ }
@@ -0,0 +1,3 @@
1
+ if ENV['CANONICAL_HOST']
2
+ Rails.application.config.middleware.use Rack::CanonicalHost, ENV['CANONICAL_HOST']
3
+ end
@@ -0,0 +1,20 @@
1
+ # ClientSideValidations Initializer
2
+
3
+ # Disabled validators. The uniqueness validator is disabled by default for security issues. Enable it on your own responsibility!
4
+ # ClientSideValidations::Config.disabled_validators = [:uniqueness]
5
+
6
+ # Uncomment to validate number format with current I18n locale
7
+ # ClientSideValidations::Config.number_format_with_locale = true
8
+
9
+ # Uncomment the following block if you want each input field to have the validation messages attached.
10
+ #
11
+ # Note: client_side_validation requires the error to be encapsulated within
12
+ # <label for="#{instance.send(:tag_id)}" class="message"></label>
13
+ #
14
+ # ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
15
+ # unless html_tag =~ /^<label/
16
+ # %{<div class="field_with_errors">#{html_tag}<label for="#{instance.send(:tag_id)}" class="message">#{instance.error_message.first}</label></div>}.html_safe
17
+ # else
18
+ # %{<div class="field_with_errors">#{html_tag}</div>}.html_safe
19
+ # end
20
+ # end
@@ -0,0 +1,6 @@
1
+ Cloudinary.config do |config|
2
+ config.cloud_name = ENV['CLOUDINARY_NAME']
3
+ config.api_key = ENV['CLOUDINARY_KEY']
4
+ config.api_secret = ENV['CLOUDINARY_SECRET']
5
+ config.cdn_subdomain = true
6
+ end
@@ -0,0 +1,9 @@
1
+ Geocoder.configure(
2
+ :lookup => :esri,
3
+ # :ip_lookup => :maxmind,
4
+ :logger => Logger.new(STDOUT, Logger::FATAL)
5
+
6
+ # calculation options
7
+ # :units => :mi, # :km for kilometers or :mi for miles
8
+ # :distances => :linear # :spherical or :linear
9
+ )
@@ -0,0 +1,33 @@
1
+ module MinimumViableProduct
2
+ module Iteration
3
+ CONFIG_FILE = File.join(Rails.root, '.iteration')
4
+
5
+ class << self
6
+ def write(json)
7
+ _file = File.open( CONFIG_FILE, "w+" )
8
+ _file.write(JSON.pretty_generate(json))
9
+ _file.close
10
+
11
+ @config = json
12
+ end
13
+
14
+ def read
15
+ @config ||= begin
16
+ JSON.parse( IO.read(CONFIG_FILE), symbolize_names: false )
17
+ rescue
18
+ write({'version' => '0.0.1'})
19
+ end
20
+ end
21
+
22
+ def bump!(bump)
23
+ config = read
24
+ config['version'] = Semantic::Version.new(config['version']).increment!(bump.downcase.to_sym).to_s
25
+ write(config)
26
+ end
27
+
28
+ def version
29
+ read["version"]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,59 @@
1
+ if ENV['ROLLBAR_SERVER_ACCESS_TOKEN']
2
+ Rollbar.configure do |config|
3
+ # Without configuration, Rollbar is enabled in all environments.
4
+ # To disable in specific environments, set config.enabled=false.
5
+
6
+ config.access_token = ENV['ROLLBAR_SERVER_ACCESS_TOKEN']
7
+
8
+ # Here we'll disable in 'test':
9
+ if Rails.env.test?
10
+ config.enabled = false
11
+ end
12
+
13
+ # By default, Rollbar will try to call the `current_user` controller method
14
+ # to fetch the logged-in user object, and then call that object's `id`,
15
+ # `username`, and `email` methods to fetch those properties. To customize:
16
+ # config.person_method = "my_current_user"
17
+ # config.person_id_method = "my_id"
18
+ # config.person_username_method = "my_username"
19
+ # config.person_email_method = "my_email"
20
+
21
+ # If you want to attach custom data to all exception and message reports,
22
+ # provide a lambda like the following. It should return a hash.
23
+ # config.custom_data_method = lambda { {:some_key => "some_value" } }
24
+
25
+ # Add exception class names to the exception_level_filters hash to
26
+ # change the level that exception is reported at. Note that if an exception
27
+ # has already been reported and logged the level will need to be changed
28
+ # via the rollbar interface.
29
+ # Valid levels: 'critical', 'error', 'warning', 'info', 'debug', 'ignore'
30
+ # 'ignore' will cause the exception to not be reported at all.
31
+ # config.exception_level_filters.merge!('MyCriticalException' => 'critical')
32
+ #
33
+ # You can also specify a callable, which will be called with the exception instance.
34
+ # config.exception_level_filters.merge!('MyCriticalException' => lambda { |e| 'critical' })
35
+
36
+ # Enable asynchronous reporting (uses girl_friday or Threading if girl_friday
37
+ # is not installed)
38
+ # config.use_async = true
39
+ # Supply your own async handler:
40
+ # config.async_handler = Proc.new { |payload|
41
+ # Thread.new { Rollbar.process_from_async_handler(payload) }
42
+ # }
43
+
44
+ # Enable asynchronous reporting (using sucker_punch)
45
+ # config.use_sucker_punch
46
+
47
+ # Enable delayed reporting (using Sidekiq)
48
+ # config.use_sidekiq
49
+ # You can supply custom Sidekiq options:
50
+ # config.use_sidekiq 'queue' => 'default'
51
+
52
+ # If you run your staging application instance in production environment then
53
+ # you'll want to override the environment reported by `Rails.env` with an
54
+ # environment variable like this: `ROLLBAR_ENV=staging`. This is a recommended
55
+ # setup for Heroku. See:
56
+ # https://devcenter.heroku.com/articles/deploying-to-a-custom-rails-environment
57
+ config.environment = ENV['ROLLBAR_ENV'] || Rails.env
58
+ end
59
+ end
@@ -0,0 +1,5 @@
1
+ if ENV['SEGMENT_WRITE_KEY']
2
+ Analytics = Segment::Analytics.new({
3
+ write_key: ENV['SEGMENT_WRITE_KEY']
4
+ })
5
+ end
@@ -0,0 +1,165 @@
1
+ # Use this setup block to configure all options available in SimpleForm.
2
+ SimpleForm.setup do |config|
3
+ # Wrappers are used by the form builder to generate a
4
+ # complete input. You can remove any component from the
5
+ # wrapper, change the order or even add your own to the
6
+ # stack. The options given below are used to wrap the
7
+ # whole input.
8
+ config.wrappers :default, class: :input,
9
+ hint_class: :field_with_hint, error_class: :field_with_errors do |b|
10
+ ## Extensions enabled by default
11
+ # Any of these extensions can be disabled for a
12
+ # given input by passing: `f.input EXTENSION_NAME => false`.
13
+ # You can make any of these extensions optional by
14
+ # renaming `b.use` to `b.optional`.
15
+
16
+ # Determines whether to use HTML5 (:email, :url, ...)
17
+ # and required attributes
18
+ b.use :html5
19
+
20
+ # Calculates placeholders automatically from I18n
21
+ # You can also pass a string as f.input placeholder: "Placeholder"
22
+ b.use :placeholder
23
+
24
+ ## Optional extensions
25
+ # They are disabled unless you pass `f.input EXTENSION_NAME => true`
26
+ # to the input. If so, they will retrieve the values from the model
27
+ # if any exists. If you want to enable any of those
28
+ # extensions by default, you can change `b.optional` to `b.use`.
29
+
30
+ # Calculates maxlength from length validations for string inputs
31
+ b.optional :maxlength
32
+
33
+ # Calculates pattern from format validations for string inputs
34
+ b.optional :pattern
35
+
36
+ # Calculates min and max from length validations for numeric inputs
37
+ b.optional :min_max
38
+
39
+ # Calculates readonly automatically from readonly attributes
40
+ b.optional :readonly
41
+
42
+ ## Inputs
43
+ b.use :label_input
44
+ b.use :hint, wrap_with: { tag: :span, class: :hint }
45
+ b.use :error, wrap_with: { tag: :span, class: :error }
46
+
47
+ ## full_messages_for
48
+ # If you want to display the full error message for the attribute, you can
49
+ # use the component :full_error, like:
50
+ #
51
+ # b.use :full_error, wrap_with: { tag: :span, class: :error }
52
+ end
53
+
54
+ # The default wrapper to be used by the FormBuilder.
55
+ config.default_wrapper = :default
56
+
57
+ # Define the way to render check boxes / radio buttons with labels.
58
+ # Defaults to :nested for bootstrap config.
59
+ # inline: input + label
60
+ # nested: label > input
61
+ config.boolean_style = :nested
62
+
63
+ # Default class for buttons
64
+ config.button_class = 'btn'
65
+
66
+ # Method used to tidy up errors. Specify any Rails Array method.
67
+ # :first lists the first message for each field.
68
+ # Use :to_sentence to list all errors for each field.
69
+ # config.error_method = :first
70
+
71
+ # Default tag used for error notification helper.
72
+ config.error_notification_tag = :div
73
+
74
+ # CSS class to add for error notification helper.
75
+ config.error_notification_class = 'error_notification'
76
+
77
+ # ID to add for error notification helper.
78
+ # config.error_notification_id = nil
79
+
80
+ # Series of attempts to detect a default label method for collection.
81
+ # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
82
+
83
+ # Series of attempts to detect a default value method for collection.
84
+ # config.collection_value_methods = [ :id, :to_s ]
85
+
86
+ # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
87
+ # config.collection_wrapper_tag = nil
88
+
89
+ # You can define the class to use on all collection wrappers. Defaulting to none.
90
+ # config.collection_wrapper_class = nil
91
+
92
+ # You can wrap each item in a collection of radio/check boxes with a tag,
93
+ # defaulting to :span.
94
+ # config.item_wrapper_tag = :span
95
+
96
+ # You can define a class to use in all item wrappers. Defaulting to none.
97
+ # config.item_wrapper_class = nil
98
+
99
+ # How the label text should be generated altogether with the required text.
100
+ config.label_text = lambda { |label, required, explicit_label| "#{label}" }
101
+
102
+ # You can define the class to use on all labels. Default is nil.
103
+ # config.label_class = nil
104
+
105
+ # You can define the default class to be used on forms. Can be overriden
106
+ # with `html: { :class }`. Defaulting to none.
107
+ # config.default_form_class = nil
108
+
109
+ # You can define which elements should obtain additional classes
110
+ # config.generate_additional_classes_for = [:wrapper, :label, :input]
111
+
112
+ # Whether attributes are required by default (or not). Default is true.
113
+ # config.required_by_default = true
114
+
115
+ # Tell browsers whether to use the native HTML5 validations (novalidate form option).
116
+ # These validations are enabled in SimpleForm's internal config but disabled by default
117
+ # in this configuration, which is recommended due to some quirks from different browsers.
118
+ # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
119
+ # change this configuration to true.
120
+ config.browser_validations = false
121
+
122
+ # Collection of methods to detect if a file type was given.
123
+ # config.file_methods = [ :mounted_as, :file?, :public_filename ]
124
+
125
+ # Custom mappings for input types. This should be a hash containing a regexp
126
+ # to match as key, and the input type that will be used when the field name
127
+ # matches the regexp as value.
128
+ # config.input_mappings = { /count/ => :integer }
129
+
130
+ # Custom wrappers for input types. This should be a hash containing an input
131
+ # type as key and the wrapper that will be used for all inputs with specified type.
132
+ # config.wrapper_mappings = { string: :prepend }
133
+
134
+ # Namespaces where SimpleForm should look for custom input classes that
135
+ # override default inputs.
136
+ # config.custom_inputs_namespaces << "CustomInputs"
137
+
138
+ # Default priority for time_zone inputs.
139
+ # config.time_zone_priority = nil
140
+
141
+ # Default priority for country inputs.
142
+ # config.country_priority = nil
143
+
144
+ # When false, do not use translations for labels.
145
+ # config.translate_labels = true
146
+
147
+ # Automatically discover new inputs in Rails' autoload path.
148
+ # config.inputs_discovery = true
149
+
150
+ # Cache SimpleForm inputs discovery
151
+ # config.cache_discovery = !Rails.env.development?
152
+
153
+ # Default class for inputs
154
+ # config.input_class = nil
155
+
156
+ # Define the default class of the input wrapper of the boolean input.
157
+ config.boolean_label_class = 'checkbox'
158
+
159
+ # Defines if the default input wrapper class should be included in radio
160
+ # collection wrappers.
161
+ # config.include_default_input_wrapper_class = true
162
+
163
+ # Defines which i18n scope will be used in Simple Form.
164
+ # config.i18n_scope = 'simple_form'
165
+ end