flowmor_router 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +175 -0
  4. data/Rakefile +34 -0
  5. data/app/controllers/application_controller.rb +2 -0
  6. data/app/controllers/static_controller.rb +2 -0
  7. data/app/models/routable_record.rb +121 -0
  8. data/bin/rails +12 -0
  9. data/config/routes.rb +21 -0
  10. data/lib/flowmor_router/engine.rb +4 -0
  11. data/lib/flowmor_router/exceptions.rb +3 -0
  12. data/lib/flowmor_router/version.rb +3 -0
  13. data/lib/flowmor_router.rb +24 -0
  14. data/lib/tasks/flowmor_router_tasks.rake +4 -0
  15. data/test/dummy/README.rdoc +28 -0
  16. data/test/dummy/Rakefile +6 -0
  17. data/test/dummy/app/assets/javascripts/application.js +13 -0
  18. data/test/dummy/app/assets/javascripts/blog.js +2 -0
  19. data/test/dummy/app/assets/javascripts/static.js +2 -0
  20. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  21. data/test/dummy/app/assets/stylesheets/blog.css +4 -0
  22. data/test/dummy/app/assets/stylesheets/static.css +4 -0
  23. data/test/dummy/app/controllers/application_controller.rb +5 -0
  24. data/test/dummy/app/controllers/blog_controller.rb +9 -0
  25. data/test/dummy/app/controllers/static_controller.rb +2 -0
  26. data/test/dummy/app/helpers/application_helper.rb +2 -0
  27. data/test/dummy/app/helpers/blog_helper.rb +2 -0
  28. data/test/dummy/app/helpers/static_helper.rb +2 -0
  29. data/test/dummy/app/models/article.rb +3 -0
  30. data/test/dummy/app/models/news_article.rb +4 -0
  31. data/test/dummy/app/models/post.rb +18 -0
  32. data/test/dummy/app/models/post_category.rb +9 -0
  33. data/test/dummy/app/views/blog/show.html.erb +1 -0
  34. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  35. data/test/dummy/app/views/static/index.html.erb +3 -0
  36. data/test/dummy/bin/bundle +3 -0
  37. data/test/dummy/bin/rails +4 -0
  38. data/test/dummy/bin/rake +4 -0
  39. data/test/dummy/config/application.rb +23 -0
  40. data/test/dummy/config/boot.rb +5 -0
  41. data/test/dummy/config/database.yml +25 -0
  42. data/test/dummy/config/environment.rb +5 -0
  43. data/test/dummy/config/environments/development.rb +37 -0
  44. data/test/dummy/config/environments/production.rb +82 -0
  45. data/test/dummy/config/environments/test.rb +39 -0
  46. data/test/dummy/config/initializers/assets.rb +8 -0
  47. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  48. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  49. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  50. data/test/dummy/config/initializers/inflections.rb +16 -0
  51. data/test/dummy/config/initializers/mime_types.rb +4 -0
  52. data/test/dummy/config/initializers/session_store.rb +3 -0
  53. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  54. data/test/dummy/config/locales/en.yml +23 -0
  55. data/test/dummy/config/routes.rb +56 -0
  56. data/test/dummy/config/secrets.yml +22 -0
  57. data/test/dummy/config.ru +4 -0
  58. data/test/dummy/db/development.sqlite3 +0 -0
  59. data/test/dummy/db/migrate/20140811154447_create_posts.rb +11 -0
  60. data/test/dummy/db/migrate/20140811155356_create_post_categories.rb +10 -0
  61. data/test/dummy/db/migrate/20140811182855_create_articles.rb +10 -0
  62. data/test/dummy/db/migrate/20140811184010_create_news_articles.rb +10 -0
  63. data/test/dummy/db/schema.rb +45 -0
  64. data/test/dummy/db/test.sqlite3 +0 -0
  65. data/test/dummy/log/development.log +6 -0
  66. data/test/dummy/log/test.log +12740 -0
  67. data/test/dummy/public/404.html +67 -0
  68. data/test/dummy/public/422.html +67 -0
  69. data/test/dummy/public/500.html +66 -0
  70. data/test/dummy/public/favicon.ico +0 -0
  71. data/test/dummy/test/controllers/static_controller_test.rb +10 -0
  72. data/test/dummy/test/fixtures/articles.yml +9 -0
  73. data/test/dummy/test/fixtures/news_articles.yml +9 -0
  74. data/test/dummy/test/fixtures/post_categories.yml +9 -0
  75. data/test/dummy/test/fixtures/posts.yml +11 -0
  76. data/test/dummy/test/helpers/blog_helper_test.rb +4 -0
  77. data/test/dummy/test/helpers/static_helper_test.rb +4 -0
  78. data/test/dummy/test/integration/routable_records_test.rb +12 -0
  79. data/test/dummy/test/models/article_test.rb +29 -0
  80. data/test/dummy/test/models/news_article_test.rb +50 -0
  81. data/test/dummy/test/models/post_category_test.rb +46 -0
  82. data/test/dummy/test/models/post_test.rb +50 -0
  83. data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  84. data/test/dummy/tmp/cache/assets/test/sprockets/2cdcb1089fe8a96b07fa1beb4356a3f2 +0 -0
  85. data/test/dummy/tmp/cache/assets/test/sprockets/2ef169e1ab9b9980404c3f7bd7b16cd1 +0 -0
  86. data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  87. data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  88. data/test/dummy/tmp/cache/assets/test/sprockets/66a7ff918272131011428741d7073461 +0 -0
  89. data/test/dummy/tmp/cache/assets/test/sprockets/66e7b4d1264df0176332685032844ce5 +0 -0
  90. data/test/dummy/tmp/cache/assets/test/sprockets/9bd4a825d7cf65dfa37efb43fe6b5aa7 +0 -0
  91. data/test/dummy/tmp/cache/assets/test/sprockets/a3ecd3c2fe5e4b3c4dd1365b4c108d06 +0 -0
  92. data/test/dummy/tmp/cache/assets/test/sprockets/c1a3b329f54c41592a0854a40f8425e0 +0 -0
  93. data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  94. data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  95. data/test/dummy/tmp/cache/assets/test/sprockets/efbfd84424b5a4f22bd23b73db9591a2 +0 -0
  96. data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  97. data/test/flowmor_router_test.rb +7 -0
  98. data/test/integration/navigation_test.rb +10 -0
  99. data/test/test_helper.rb +15 -0
  100. metadata +257 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2c0e0b8f28d14381f316e7b078f003b6b34ad4e3
4
+ data.tar.gz: d3e74563ae117dd9845b403d40dda5fb4959b602
5
+ SHA512:
6
+ metadata.gz: d419cdd6d363da16774c775ce50a650b8e6efa4dcd5ffdd359cc6c752f8a321fb4661e3f71069eb2bf6d2a5def06ee643426d9b7586745f256021348b82c7149
7
+ data.tar.gz: cebc0c41d34de490877241f6c85788710b0f281f47d4335d2930a9fc815d01219f9df33c0df69ce7a19862a017048f3c84620a364f00117ebe78dbf876221a6c
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Michael Lang
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,175 @@
1
+ # FlowmorRouter
2
+
3
+ FlowmorRouter is a Rails::Engine that enables ActiveRecord Models to route themselves in Rails 4.x applications. For example:
4
+
5
+ ```ruby
6
+ class Post < RoutableRecord
7
+ end
8
+
9
+ p = Post.create(title: "My First Post")
10
+ puts p.name # => "my-first-example"
11
+ puts p.path # => "/posts/my-first-example"
12
+ ```
13
+
14
+ or in a view where PostCategory has_many :posts
15
+
16
+ ```haml
17
+ - PostCategory.all.each do |category|
18
+ %h3= link_to category.title, category.path
19
+ %ul
20
+ - category.posts.recently_published.each do |post|
21
+ %li= link_to post.title, post.path
22
+ ```
23
+
24
+ FlowmorRouter also supports static pages. All you have to do is create an app/views/static folder and place templates in that folder. Routes are automatically generated and served by the StaticController. Currently, this only goes one level deep. That is, sub-directories of static not yet implemented.
25
+
26
+ If you're blogging with markdown or other file-based approaches, you'll appreciate how easy it is to reference your posts in those static views with linking:
27
+
28
+ ```haml
29
+ =%h1 About
30
+ %p Please be sure to read my post, #{link_to "How to Use Flowmor Router", post_how_to_use_flowmor_router_path}
31
+ ```
32
+
33
+ Every model instance's route is named after the model and name.
34
+
35
+ ## State of the project
36
+
37
+ ### 0.0.1
38
+
39
+ Its got enough functionality to work really well for me [(mwlang)](https://github.com/mwlang) in its current form. Its a simple implementation with relatively few lines of code, adequately test covered. It works and is used in production on a handful of sites. You can see it in action on [my personal site](http://codeconnoisseur.org) and [business site](http://cybrains.net).
40
+
41
+ ### Is it For You?
42
+
43
+ This isn't for everyone. It does build routes from objects in the database. It does provide functionality similar to [friendly_id](https://github.com/norman/friendly_id) or by simply redefining the id of a model with AR's #to_param. If you run multiple instances of an application, you'll need to take care of syncing when the database is updated. The simplest way to do this is by adding Post.reload_routes (for example) to the before_filter callback of the controller. Sounds like a performance killer, but its really not. Just think every time you refresh during development that the routes are reloaded!
44
+
45
+
46
+
47
+ ### To Install
48
+
49
+ Add to your Rails project Gemfile:
50
+
51
+ ```
52
+ gem 'flowmor_router'
53
+ ```
54
+
55
+ And then run the `bundle install` command.
56
+
57
+ ## Convention over Configuration
58
+
59
+ I wanted a *simple* implementation and library to work with, so the convention is the model has a `title` field and a `name` field. You (or your user) sets the title and the name field gets auto-populated with a routable name. Hyphens are used instead of underscores because Google Webmaster Guidelines favors hyphens over underscores for SEO.
60
+
61
+ For example, "FlowmorRouter, the amazing little engine that could" will populate the name field with 'flowmor-router-the-amazing-little-engine-that-could'. The controller by convention will have the same name as the model's name while the default action will be the #show action on that controller. If you have a Post model, then its expected that your application has a PostController. You're expected to provide the controller implementation. Here's an example:
62
+
63
+ ```ruby
64
+ class PostController < ApplicationController
65
+ before_action :set_post, only: [:show]
66
+
67
+ private
68
+
69
+ def set_post
70
+ @post = Post.find(params[:id])
71
+ end
72
+ end
73
+ ```
74
+
75
+ Note that you can find the record using the params[:id] which will be the actual id of the record because the routes are constructed specific to the ID for the object to be fetched. This way we can skip the whole #to_param and params[:id].to_i non-sense or doing a more expensive SQL query and indexing on real titles, names, etc. The other thing I like about this approach is that it plays nice with other toys like ActiveAdmin, which can get finicky about those #to_param changes.
76
+
77
+ To make an ActiveRecord model routable, change the inheritance after generating the model from ActiveRecord::Base to RoutableRecord like so:
78
+
79
+ ```ruby
80
+ class Post < RoutableRecord
81
+ # ...
82
+ end
83
+ ```
84
+
85
+ ### Conventions Suck, I Really Want to Customize!
86
+
87
+ Ok, here's how to do it. To change the field that the route name is derived from:
88
+
89
+ ```ruby
90
+ class NewsArticle < RoutableRecord
91
+ set_derived_name_field :caption # changes from :title
92
+ set_name_field :slug # changes from :name
93
+ end
94
+ ```
95
+ To change the controller and action:
96
+
97
+ ```ruby
98
+ class PostCategory < RoutableRecord
99
+ set_controller_action "blog#category"
100
+ end
101
+ ```
102
+
103
+ To change how the route and route name are constructed (say you have Post that belongs_to PostCategory and need to avoid naming collision should two posts have same title, but belong to different categories):
104
+
105
+ ```ruby
106
+ class PostCategory < RoutableRecord
107
+ has_many :posts, foreign_key: "category_id"
108
+
109
+ set_controller_action "blog#category"
110
+
111
+ # Not necessary here, but shows you how to change the route's model name.
112
+ # Here, we change "post_category" (the default) to "category"
113
+ # For example, PostCategory.create(title: "General"), the
114
+ # route name becomes "category_general" instead of "post_category_general"
115
+ def route_model
116
+ "category"
117
+ end
118
+ end
119
+
120
+ class Post < RoutableRecord
121
+ belongs_to :category, class_name: "PostCategory", counter_cache: true
122
+
123
+ set_controller_action "blog#show"
124
+
125
+ # Assuming you have a Post.create(title: "Some Title", category: PostCategory.create(title: "General"))
126
+ # The names of the post route's name changes from post_some_title to post_general_some_title by
127
+ # appending category name to the route name prefix
128
+ def route_name_prefix
129
+ super + "_#{category_name}"
130
+ end
131
+
132
+ # as a bonus, automatically "categorize" as "general" when no category assigned.
133
+ def category_name
134
+ category.try(:name) || 'general'
135
+ end
136
+
137
+ # The route is also changed in this example from /posts/some-title to /general/some-title
138
+ def route
139
+ "/#{category_name}/#{name}"
140
+ end
141
+ end
142
+ ```
143
+
144
+ If you need to get any fancier than that, then just about everything you need can be found in the [app/models/routable_record.rb](https://github.com/mwlang/flowmor_router/blob/master/app/models/routable_record.rb) implementation.
145
+
146
+ ### TODO and Contributing
147
+
148
+ This is largely an extraction of functionality from multiple Rails projects. As such, it has the features I needed to fully extract to the engine. However, some possible enhancements came to mind as I pulled this together:
149
+
150
+ * if a model belongs_to another model, then use ActiveRecord's Reflections to automatically build richer routes
151
+ * scan sub-directories under static to build nested pages that the static_controller can serve.
152
+ * instead of routing *all* RoutableRecord's, add "routable" scope that defaults to *all* but can be easily changed by redefining the :routable scope on the descendant model class.
153
+ * potentially optimize the route generator to only update the routes that actually changed (currently all routes are triggered to reload).
154
+
155
+ Please don't hold your breath for me, though. Unless [I need 'em for a specific project](http://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it), they won't happen. If you need it, implement and contribute back with pull request. I'll take enhancements as long as they're test covered and don't break backwards compatibility.
156
+
157
+ ## Testing
158
+
159
+ Testing makes use of a dummy Rails app, which can be found under [test/dummy folder](https://github.com/mwlang/flowmor_router/tree/master/test/dummy). The test scripts for this app is under [test/dummy/test](https://github.com/mwlang/flowmor_router/tree/master/test/dummy/test) and you'll find many of the examples presented above as working examples in this dummy app.
160
+
161
+ To test for the first time, you'll need to initialize the database with:
162
+
163
+ ```
164
+ RAILS_ENV=test rake db:migrate
165
+ ```
166
+
167
+ Following this, you can run the test suite with:
168
+
169
+ ```
170
+ rake test
171
+ ```
172
+
173
+ ### LICENSE
174
+
175
+ This project uses MIT-LICENSE. Please see the MIT-LICENSE file.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
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 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'FlowmorRouter'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,2 @@
1
+ class StaticController < ApplicationController
2
+ end
@@ -0,0 +1,121 @@
1
+ class RoutableRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+
4
+ def self.route_model
5
+ name.underscore.downcase
6
+ end
7
+
8
+ def route_model
9
+ self.class.route_model
10
+ end
11
+
12
+ def self.set_controller_action value
13
+ @controller_action = value
14
+ end
15
+
16
+ def self.default_controller_action
17
+ "#{route_model.underscore}#show"
18
+ end
19
+
20
+ def self.controller_action
21
+ @controller_action || default_controller_action
22
+ end
23
+
24
+ def controller_action
25
+ self.class.controller_action
26
+ end
27
+
28
+ def self.set_derived_name_field value
29
+ @derived_name_field = value
30
+ end
31
+
32
+ def self.derived_name_field
33
+ @derived_name_field || 'title'
34
+ end
35
+
36
+ def derived_name_field
37
+ self.class.derived_name_field
38
+ end
39
+
40
+ def derived_name_field_value
41
+ if respond_to? derived_name_field
42
+ send(derived_name_field)
43
+ else
44
+ raise RuntimeError
45
+ end
46
+ end
47
+
48
+ def self.set_name_field value
49
+ @name_field = value
50
+ end
51
+
52
+ def self.name_field
53
+ @name_field || 'name'
54
+ end
55
+
56
+ def name_field
57
+ self.class.name_field
58
+ end
59
+
60
+ def name_field_value
61
+ attributes[name_field]
62
+ end
63
+
64
+ include Rails.application.routes.url_helpers
65
+
66
+ after_save :reload_routes
67
+ before_save :populate_name
68
+
69
+ def route_name_prefix
70
+ "#{route_model.pluralize}"
71
+ end
72
+
73
+ def route_name
74
+ name_suffix = new_name_value
75
+ raise UnroutableRecord if name_suffix.blank?
76
+
77
+ "#{route_name_prefix}_#{name_suffix}".underscore
78
+ end
79
+
80
+ def route_prefix
81
+ "/#{route_model.pluralize.gsub('_', '-')}"
82
+ end
83
+
84
+ def route
85
+ "#{route_prefix}/#{new_name_value}"
86
+ end
87
+
88
+ def default_url_options
89
+ { :host => Thread.current[:host], :port => Thread.current[:port] }
90
+ end
91
+
92
+ def url
93
+ send("#{route_name}_url", default_url_options)
94
+ end
95
+
96
+ def path
97
+ send("#{route_name}_path")
98
+ end
99
+
100
+ def new_name_value
101
+ if value = derived_name_field_value and !value.blank?
102
+ value.downcase.gsub(/[^\w\s\d\_\-]/,'').gsub(/\s\s+/,' ').gsub(/[^\w\d]/, '-')
103
+ else
104
+ raise FlowmorRouter::UnroutableRecord if value.blank?
105
+ end
106
+ end
107
+
108
+ def name_field_changed?
109
+ new_name_value != attributes[name_field]
110
+ end
111
+
112
+ def populate_name
113
+ if attributes[name_field].blank? || name_field_changed?
114
+ send("#{name_field}=", new_name_value)
115
+ end
116
+ end
117
+
118
+ def reload_routes
119
+ Rails.application.routes_reloader.reload!
120
+ end
121
+ end
data/bin/rails ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/flowmor_router/engine', __FILE__)
6
+
7
+ # Set up gems listed in the Gemfile.
8
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
10
+
11
+ require 'rails/all'
12
+ require 'rails/engine/commands'
data/config/routes.rb ADDED
@@ -0,0 +1,21 @@
1
+ Rails.application.routes.draw do
2
+
3
+ # Routes from RoutableRecord descendants
4
+ RoutableRecord.descendants.each do |model|
5
+ model.all.each do |record|
6
+ get record.route,
7
+ to: record.controller_action,
8
+ defaults: { id: record.id },
9
+ as: record.route_name
10
+ end
11
+ end
12
+
13
+ # Routes from app/view/static
14
+ Dir.glob(File.join(Rails.root, 'app', 'views', 'static', '*')).reject{|r| File.directory?(r)}.each do |fn|
15
+ route = File.basename fn.split(".").first
16
+ # ignore partials
17
+ if route[0] != "_"
18
+ get("/#{route}", to: "static##{route}", as: "static_#{route}")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module FlowmorRouter
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module FlowmorRouter
2
+ class UnroutableRecord < RuntimeError; end
3
+ end
@@ -0,0 +1,3 @@
1
+ module FlowmorRouter
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ require "flowmor_router/engine"
2
+ require "flowmor_router/exceptions"
3
+
4
+ module FlowmorRouter
5
+
6
+ class HostAndPortGrabber
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ req = Rack::Request.new(env)
13
+ Thread.current[:host] = req.host
14
+ Thread.current[:port] = req.port
15
+
16
+ @app.call(env)
17
+ end
18
+ end
19
+
20
+ class Engine < ::Rails::Engine
21
+ config.flowmor_router = FlowmorRouter
22
+ config.app_middleware.insert_after(ActionDispatch::ParamsParser, FlowmorRouter::HostAndPortGrabber)
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :flowmor_router do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -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 File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
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 vendor/assets/javascripts of plugins, if any, 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.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -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 vendor/assets/stylesheets of plugins, if any, 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 styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,9 @@
1
+ class BlogController < ApplicationController
2
+ before_action :set_post, only: [:show]
3
+
4
+ private
5
+
6
+ def set_post
7
+ @post = Post.find(params[:id])
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ class StaticController < ApplicationController
2
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module BlogHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module StaticHelper
2
+ end
@@ -0,0 +1,3 @@
1
+ class Article < RoutableRecord
2
+
3
+ end
@@ -0,0 +1,4 @@
1
+ class NewsArticle < RoutableRecord
2
+ set_derived_name_field :caption
3
+ set_name_field :slug
4
+ end
@@ -0,0 +1,18 @@
1
+ class Post < RoutableRecord
2
+ belongs_to :category, class_name: "PostCategory", counter_cache: true
3
+
4
+ set_controller_action "blog#show"
5
+
6
+ # Appending category name to the route name prefix
7
+ def route_name_prefix
8
+ super + "_#{category_name}"
9
+ end
10
+
11
+ def category_name
12
+ category.try(:name) || 'general'
13
+ end
14
+
15
+ def route
16
+ "/#{category_name}/#{name}"
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ class PostCategory < RoutableRecord
2
+ has_many :posts, foreign_key: "category_id"
3
+
4
+ set_controller_action "blog#category"
5
+
6
+ def route_model
7
+ "category"
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ <h1><%= @post.title %></h1>
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,3 @@
1
+ <h1>Static Page Example</h1>
2
+
3
+ <p>It Works!</p>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
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