cadmus 0.4.4 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +15 -0
- data/README.md +152 -99
- data/app/views/cadmus/pages/_form.html.erb +1 -1
- data/lib/cadmus/controller_extensions.rb +7 -3
- data/lib/cadmus/page.rb +1 -1
- data/lib/cadmus/routing.rb +2 -2
- data/lib/cadmus/slugs.rb +2 -2
- data/lib/cadmus/version.rb +1 -1
- metadata +2 -3
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## cadmus 0.4.6 (07-15-2013)
|
2
|
+
|
3
|
+
* Changes for Rails 4 compatibility:
|
4
|
+
** Allow PUT or PATCH for the update action
|
5
|
+
** Implement a page_params protected method in page controllers, which you can override to get strong_parameters support
|
6
|
+
|
7
|
+
## cadmus 0.4.5 (03-04-2013)
|
8
|
+
|
9
|
+
* Change all the other uses of ^ and $ in regexes to \A and \z
|
10
|
+
* Change scope to use a lambda for Rails 4 compatibility
|
11
|
+
|
12
|
+
## cadmus 0.4.4 (03-04-2013)
|
13
|
+
|
14
|
+
* Change some uses of ^ and $ in regexes to \A and \z
|
15
|
+
|
1
16
|
## cadmus 0.4.3 (06-17-2012)
|
2
17
|
|
3
18
|
* Add a cadmus:views generator to make view customization easier
|
data/README.md
CHANGED
@@ -21,8 +21,10 @@ instead, just use forward-slash characters in the page slug to simulate folders,
|
|
21
21
|
|
22
22
|
First, add Cadmus to your Gemfile:
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
```ruby
|
25
|
+
gem 'cadmus'
|
26
|
+
gem 'redcarpet' # (required only if you intend to use Cadmus' Markdown support)
|
27
|
+
```
|
26
28
|
|
27
29
|
The next step is to create a Page model. Your app can have multiple Page models if you like, but for this example, we'll just
|
28
30
|
create one.
|
@@ -32,24 +34,55 @@ create one.
|
|
32
34
|
You'll need to tweak the generated migration and model slightly. In the migration, after the `create_pages` block, add a
|
33
35
|
unique index on the parent and slug columns:
|
34
36
|
|
35
|
-
|
37
|
+
```ruby
|
38
|
+
add_index :pages, [:parent_type, :parent_id, :slug], :unique => true
|
39
|
+
```
|
36
40
|
|
37
41
|
And in the model, add a `cadmus_page` declaration:
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
```ruby
|
44
|
+
class Page < ActiveRecord::Base
|
45
|
+
cadmus_page
|
46
|
+
end
|
47
|
+
```
|
42
48
|
|
43
49
|
You'll need a controller to deal with your pages. Here's a minimal example of one:
|
44
50
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
```ruby
|
52
|
+
class PagesController < ApplicationController
|
53
|
+
include Cadmus::PagesController
|
54
|
+
|
55
|
+
protected
|
56
|
+
def page_class
|
57
|
+
Page
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
If you're on Rails 4 (or using the `strong_parameters` gem) you'll probably want to use forbidden attributes protection.
|
63
|
+
Here's how you do that:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
class Page < ActiveRecord::Base
|
67
|
+
include ActiveModel::ForbiddenAttributesProtection
|
68
|
+
cadmus_page
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class PagesController < ApplicationController
|
74
|
+
include Cadmus::PagesController
|
75
|
+
|
76
|
+
protected
|
77
|
+
def page_params
|
78
|
+
params.require(:page).permit(:name, :slug, :content)
|
79
|
+
end
|
80
|
+
|
81
|
+
def page_class
|
82
|
+
Page
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
53
86
|
|
54
87
|
`Cadmus::PagesController` automatically adds the seven RESTful resource methods to your controller. It requires that you
|
55
88
|
define a `page_class` method that returns the class for pages it's dealing with. (This could potentially return different
|
@@ -58,9 +91,11 @@ types of page.)
|
|
58
91
|
|
59
92
|
Finally, you'll need to create routes for this controller. Cadmus provides a built-in helper for that:
|
60
93
|
|
61
|
-
|
62
|
-
|
63
|
-
|
94
|
+
```ruby
|
95
|
+
MyApp::Application.routes.draw do
|
96
|
+
cadmus_pages
|
97
|
+
end
|
98
|
+
```
|
64
99
|
|
65
100
|
This will create the following routes:
|
66
101
|
|
@@ -68,6 +103,7 @@ This will create the following routes:
|
|
68
103
|
* GET /pages/new => PagesController#new
|
69
104
|
* POST /pages => PagesController#create
|
70
105
|
* GET /pages/slug => PagesController#show
|
106
|
+
* PATCH /pages/slug => PagesController#update
|
71
107
|
* PUT /pages/slug => PagesController#update
|
72
108
|
* DELETE /pages/slug => PagesController#destroy
|
73
109
|
|
@@ -76,26 +112,30 @@ This will create the following routes:
|
|
76
112
|
The pages controller is where you'll need to hook into any authorization or authentication system your app might use.
|
77
113
|
We use CanCan, so here's an example of how we do that:
|
78
114
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
115
|
+
```ruby
|
116
|
+
class PagesController < ApplicationController
|
117
|
+
include Cadmus::PagesController
|
118
|
+
|
119
|
+
authorize_resource :page
|
120
|
+
|
121
|
+
protected
|
122
|
+
def page_class
|
123
|
+
Page
|
124
|
+
end
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
class Ability
|
130
|
+
def initialize(user)
|
131
|
+
can :read, Page
|
132
|
+
return unless user
|
89
133
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
# in this example, we've added an owner_id column to our Page model
|
96
|
-
can :manage, Page, :owner_id => user.id
|
97
|
-
end
|
98
|
-
end
|
134
|
+
# in this example, we've added an owner_id column to our Page model
|
135
|
+
can :manage, Page, :owner_id => user.id
|
136
|
+
end
|
137
|
+
end
|
138
|
+
```
|
99
139
|
|
100
140
|
Easy-peasy. You can use other authorization plugins in a similar way - with Cadmus, you control the CMS models,
|
101
141
|
controllers and routes, so you can add whatever code is appropriate for your app.
|
@@ -108,49 +148,55 @@ content pages as well.
|
|
108
148
|
|
109
149
|
You already have the following routes set up in your routes.rb file:
|
110
150
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
151
|
+
```ruby
|
152
|
+
DugoutCoach::Application.routes.draw do
|
153
|
+
resources :teams do
|
154
|
+
resources :players
|
155
|
+
resources :schedule
|
156
|
+
end
|
157
|
+
|
158
|
+
cadmus_pages # for global pages on your site
|
159
|
+
end
|
160
|
+
```
|
119
161
|
|
120
162
|
So, for example, the URL for the Cambridge Cosmonauts might be http://dugoutcoach.net/teams/cosmonauts. They also
|
121
163
|
have http://dugoutcoach.net/teams/cosmonauts/players and http://dugoutcoach.net/teams/cosmonauts/schedule.
|
122
164
|
|
123
165
|
You can add a "pages" namespace pretty easily:
|
124
166
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
167
|
+
```ruby
|
168
|
+
DugoutCoach::Application.routes.draw do
|
169
|
+
resources :teams do
|
170
|
+
resources :players
|
171
|
+
resources :schedule
|
172
|
+
cadmus_pages :controller => :team_pages
|
173
|
+
end
|
174
|
+
|
175
|
+
cadmus_pages
|
176
|
+
end
|
177
|
+
```
|
134
178
|
|
135
179
|
Now you have a way of separating team-specific pages from global pages on the site. The URLs for these pages might be,
|
136
180
|
for example, http://dugoutcoach.net/teams/cosmonauts/directions, or
|
137
181
|
http://dugoutcoach.net/teams/cosmonauts/promotions/free-hat-day (remember, Cadmus slugs can contain slashes). We'll
|
138
182
|
now need a TeamPages controller to handle these:
|
139
183
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
184
|
+
```ruby
|
185
|
+
class TeamPagesController < ApplicationController
|
186
|
+
include Cadmus::PagesController
|
187
|
+
|
188
|
+
self.page_parent_class = Team # page's parent is a Team
|
189
|
+
self.page_parent_name = "team" # parent ID is in params[:team_id]
|
190
|
+
self.find_parent_by = "slug" # parent ID is the Team's "slug" field rather than "id"
|
191
|
+
|
192
|
+
authorize_resource :page
|
193
|
+
|
194
|
+
protected
|
195
|
+
def page_class
|
196
|
+
Page
|
197
|
+
end
|
198
|
+
end
|
199
|
+
```
|
154
200
|
|
155
201
|
Note that for this example, we've kept the same `Page` class for both controllers. We could have also created a
|
156
202
|
separate `TeamPage` model, but that's not required.
|
@@ -162,15 +208,17 @@ in them just because they created them themselves?
|
|
162
208
|
|
163
209
|
Chill out, Cosmonauts. Cadmus makes it easy:
|
164
210
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
211
|
+
```ruby
|
212
|
+
DugoutCoach::Application.routes.draw do
|
213
|
+
resources :teams do
|
214
|
+
resources :players
|
215
|
+
resources :schedule
|
216
|
+
cadmus_pages :controller => :team_pages, :shallow => true
|
217
|
+
end
|
218
|
+
|
219
|
+
cadmus_pages
|
220
|
+
end
|
221
|
+
```
|
174
222
|
|
175
223
|
Now the PagesController's `show`, `edit`, `update`, and `destroy` actions don't use the "/pages/" part of the URL. The
|
176
224
|
URLs now look like this:
|
@@ -203,35 +251,40 @@ help them by providing them with a Liquid template variable they can use like so
|
|
203
251
|
|
204
252
|
To do this, you'll need to expose `team` as a Liquid assign variable:
|
205
253
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
254
|
+
```ruby
|
255
|
+
class TeamPagesController < ApplicationController
|
256
|
+
include Cadmus::PagesController
|
257
|
+
|
258
|
+
self.page_parent_class = Team # page's parent is a Team
|
259
|
+
self.page_parent_name = "team" # parent ID is in params[:team_id]
|
260
|
+
self.find_parent_by = "slug" # parent ID is the Team's "slug" field rather than "id"
|
261
|
+
|
262
|
+
authorize_resource :page
|
263
|
+
|
264
|
+
protected
|
265
|
+
|
266
|
+
def page_class
|
267
|
+
Page
|
268
|
+
end
|
269
|
+
|
270
|
+
def liquid_assigns
|
271
|
+
{ :team => @page.parent }
|
272
|
+
end
|
273
|
+
end
|
274
|
+
```
|
224
275
|
|
225
276
|
Defining a `liquid_assigns` method will cause Cadmus to use the return value of that method as the Liquid assigns hash.
|
226
277
|
(Similarly, you can define `liquid_filters` and `liquid_registers` methods that do what they say on the tin.)
|
227
278
|
|
228
279
|
You'll also need to make your Team model usable from Liquid. The simplest way to do that is using `liquid_methods`:
|
229
280
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
281
|
+
```ruby
|
282
|
+
class Team < ActiveRecord::Base
|
283
|
+
liquid_methods :name, :uniform_color
|
284
|
+
|
285
|
+
# everything else in your model...
|
286
|
+
end
|
287
|
+
```
|
235
288
|
|
236
289
|
You could also define a `to_liquid` method that returns a `Liquid::Drop` subclass for Teams, if you need to do things
|
237
290
|
more complicated than just return data values.
|
@@ -17,7 +17,7 @@
|
|
17
17
|
<div class="field">
|
18
18
|
<%= f.label :slug, "URL" %>
|
19
19
|
<p>
|
20
|
-
<%= url_for(:action => 'show', :page_glob => "slug", :only_path => false).sub(/slug
|
20
|
+
<%= url_for(:action => 'show', :page_glob => "slug", :only_path => false).sub(/slug\Z/, '') %>
|
21
21
|
<%= f.text_field :slug %>
|
22
22
|
</p>
|
23
23
|
</div>
|
@@ -94,7 +94,7 @@ module Cadmus
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def new
|
97
|
-
@page = page_scope.new(
|
97
|
+
@page = page_scope.new(page_params)
|
98
98
|
|
99
99
|
respond_to do |format|
|
100
100
|
format.html { render 'cadmus/pages/new' }
|
@@ -108,7 +108,7 @@ module Cadmus
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def create
|
111
|
-
@page = page_scope.new(
|
111
|
+
@page = page_scope.new(page_params)
|
112
112
|
|
113
113
|
respond_to do |format|
|
114
114
|
if @page.save
|
@@ -126,7 +126,7 @@ module Cadmus
|
|
126
126
|
|
127
127
|
def update
|
128
128
|
respond_to do |format|
|
129
|
-
if @page.update_attributes(
|
129
|
+
if @page.update_attributes(page_params)
|
130
130
|
dest = { :action => 'show', :page_glob => @page.slug }
|
131
131
|
format.html { redirect_to(dest, :notice => 'Page was successfully updated.') }
|
132
132
|
format.xml { head :ok }
|
@@ -211,6 +211,10 @@ module Cadmus
|
|
211
211
|
@page_scope ||= page_parent ? page_parent.pages : page_class.global
|
212
212
|
end
|
213
213
|
|
214
|
+
def page_params
|
215
|
+
params[:page]
|
216
|
+
end
|
217
|
+
|
214
218
|
def load_parent_and_page
|
215
219
|
if params[:page_glob]
|
216
220
|
@page = page_scope.find_by_slug(params[:page_glob])
|
data/lib/cadmus/page.rb
CHANGED
@@ -38,7 +38,7 @@ module Cadmus
|
|
38
38
|
validates_uniqueness_of slug_field, :scope => [:parent_id, :parent_type]
|
39
39
|
validates_exclusion_of slug_field, :in => %w(pages edit)
|
40
40
|
|
41
|
-
scope :global,
|
41
|
+
scope :global, lambda { where(:parent_id => nil, :parent_type => nil) }
|
42
42
|
|
43
43
|
class_eval do
|
44
44
|
def liquid_template
|
data/lib/cadmus/routing.rb
CHANGED
@@ -16,7 +16,7 @@ module Cadmus
|
|
16
16
|
# application. So we have to always pass this constraint if we're testing.
|
17
17
|
return true if page_glob.nil? && Rails.env.test?
|
18
18
|
|
19
|
-
page_glob.sub(
|
19
|
+
page_glob.sub(/\A\//, '').split(/\//).all? do |part|
|
20
20
|
part =~ /\A[a-z][a-z0-9\-]*\z/
|
21
21
|
end
|
22
22
|
end
|
@@ -55,7 +55,7 @@ ActionDispatch::Routing::Mapper.class_eval do
|
|
55
55
|
page_actions = Proc.new do
|
56
56
|
get "*page_glob/edit" => "#{controller}#edit", :as => 'edit_page', :constraints => slug_constraint
|
57
57
|
get "*page_glob" => "#{controller}#show", :as => 'page', :constraints => slug_constraint
|
58
|
-
|
58
|
+
match "*page_glob" => "#{controller}#update", :constraints => slug_constraint, :via => [:put, :patch]
|
59
59
|
delete "*page_glob" => "#{controller}#destroy", :constraints => slug_constraint
|
60
60
|
end
|
61
61
|
|
data/lib/cadmus/slugs.rb
CHANGED
@@ -8,7 +8,7 @@ module Cadmus
|
|
8
8
|
#
|
9
9
|
# For example, +about-us/people+, +special-deals+, and +winter-2012+ are all valid slugs, but
|
10
10
|
# +3-things+, +123+, +nobody-lives-here!+, and +/root-page+ aren't.
|
11
|
-
SLUG_REGEX =
|
11
|
+
SLUG_REGEX = /\A([a-z][a-z0-9\-]*\/)*[a-z][a-z0-9\-]*\z/
|
12
12
|
|
13
13
|
# Converts a string to a valid slug part by changing all whitespace to hyphens, converting all
|
14
14
|
# upper-case letters to lower-case, removing all remaining non-alphanumeric, non-hyphen
|
@@ -19,7 +19,7 @@ module Cadmus
|
|
19
19
|
# * "21 guns" becomes "guns"
|
20
20
|
# * "We love you, Conrad!!!1" becomes "we-love-you-conrad1"
|
21
21
|
def self.slugify(string)
|
22
|
-
string.to_s.downcase.gsub(/\s+/, '-').gsub(/[^a-z0-9\-]/, '').sub(
|
22
|
+
string.to_s.downcase.gsub(/\s+/, '-').gsub(/[^a-z0-9\-]/, '').sub(/\A[^a-z]+/, '')
|
23
23
|
end
|
24
24
|
|
25
25
|
# An extension for ActiveRecord::Base that adds a +has_slug+ method. This can also be
|
data/lib/cadmus/version.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: cadmus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.4.
|
5
|
+
version: 0.4.6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Nat Budin
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-07-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -102,4 +102,3 @@ signing_key:
|
|
102
102
|
specification_version: 3
|
103
103
|
summary: Embeddable CMS for Rails 3 apps
|
104
104
|
test_files: []
|
105
|
-
has_rdoc:
|