flowmor_router 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +175 -0
- data/Rakefile +34 -0
- data/app/controllers/application_controller.rb +2 -0
- data/app/controllers/static_controller.rb +2 -0
- data/app/models/routable_record.rb +121 -0
- data/bin/rails +12 -0
- data/config/routes.rb +21 -0
- data/lib/flowmor_router/engine.rb +4 -0
- data/lib/flowmor_router/exceptions.rb +3 -0
- data/lib/flowmor_router/version.rb +3 -0
- data/lib/flowmor_router.rb +24 -0
- data/lib/tasks/flowmor_router_tasks.rake +4 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/javascripts/blog.js +2 -0
- data/test/dummy/app/assets/javascripts/static.js +2 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/assets/stylesheets/blog.css +4 -0
- data/test/dummy/app/assets/stylesheets/static.css +4 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/blog_controller.rb +9 -0
- data/test/dummy/app/controllers/static_controller.rb +2 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/blog_helper.rb +2 -0
- data/test/dummy/app/helpers/static_helper.rb +2 -0
- data/test/dummy/app/models/article.rb +3 -0
- data/test/dummy/app/models/news_article.rb +4 -0
- data/test/dummy/app/models/post.rb +18 -0
- data/test/dummy/app/models/post_category.rb +9 -0
- data/test/dummy/app/views/blog/show.html.erb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/static/index.html.erb +3 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +82 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/assets.rb +8 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20140811154447_create_posts.rb +11 -0
- data/test/dummy/db/migrate/20140811155356_create_post_categories.rb +10 -0
- data/test/dummy/db/migrate/20140811182855_create_articles.rb +10 -0
- data/test/dummy/db/migrate/20140811184010_create_news_articles.rb +10 -0
- data/test/dummy/db/schema.rb +45 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +6 -0
- data/test/dummy/log/test.log +12740 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/test/controllers/static_controller_test.rb +10 -0
- data/test/dummy/test/fixtures/articles.yml +9 -0
- data/test/dummy/test/fixtures/news_articles.yml +9 -0
- data/test/dummy/test/fixtures/post_categories.yml +9 -0
- data/test/dummy/test/fixtures/posts.yml +11 -0
- data/test/dummy/test/helpers/blog_helper_test.rb +4 -0
- data/test/dummy/test/helpers/static_helper_test.rb +4 -0
- data/test/dummy/test/integration/routable_records_test.rb +12 -0
- data/test/dummy/test/models/article_test.rb +29 -0
- data/test/dummy/test/models/news_article_test.rb +50 -0
- data/test/dummy/test/models/post_category_test.rb +46 -0
- data/test/dummy/test/models/post_test.rb +50 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2cdcb1089fe8a96b07fa1beb4356a3f2 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2ef169e1ab9b9980404c3f7bd7b16cd1 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/66a7ff918272131011428741d7073461 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/66e7b4d1264df0176332685032844ce5 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/9bd4a825d7cf65dfa37efb43fe6b5aa7 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/a3ecd3c2fe5e4b3c4dd1365b4c108d06 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/c1a3b329f54c41592a0854a40f8425e0 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/efbfd84424b5a4f22bd23b73db9591a2 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/flowmor_router_test.rb +7 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/test_helper.rb +15 -0
- 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,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,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,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>.
|
data/test/dummy/Rakefile
ADDED
@@ -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,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,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 @@
|
|
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>
|
data/test/dummy/bin/rake
ADDED