cadmus 0.4.4 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|