merbiful-release 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,12 +1,11 @@
1
1
  require 'rubygems'
2
2
  require 'rake/gempackagetask'
3
3
  require 'spec'
4
- require 'spec/rake/spectask'
5
4
  require 'pathname'
6
5
 
7
6
  PLUGIN = "merbiful-release"
8
7
  NAME = "merbiful-release"
9
- GEM_VERSION = "0.0.2"
8
+ GEM_VERSION = "0.0.3"
10
9
  AUTHOR = "Martin Kihlgren"
11
10
  EMAIL = "martin@wemind.se"
12
11
  HOMEPAGE = ""
@@ -38,7 +37,7 @@ task :install => [:package] do
38
37
  end
39
38
 
40
39
  desc "Run specifications"
41
- Spec::Rake::SpecTask.new('spec') do |t|
42
- t.spec_opts = ["--format", "specdoc", "--colour"]
43
- t.spec_files = Pathname.glob(Pathname.new(__FILE__).parent.join("spec").join("**").join("*_spec.rb"))
40
+ task :spec do
41
+ Dir.chdir(File.join(File.dirname(__FILE__), "spec"))
42
+ system("rake spec")
44
43
  end
@@ -122,17 +122,13 @@ module Merbiful
122
122
 
123
123
  def destroy_page
124
124
  page = Page.get(params[:page_id])
125
- page.versions.each do |version|
126
- version.css_nesses.destroy!
127
- version.js_nesses.destroy!
128
- version.destroy
129
- end
130
125
  page.destroy
131
126
  redirect url(:merbiful_admin, :action => "pages")
132
127
  end
133
128
 
134
129
  def upload_image
135
130
  path = Pathname.new(File.join(Merb.root, "public", "images", File.basename(params[:image][:filename])))
131
+ raise "H4xx0r" unless path.to_s.index(Pathname.new(Merb.root).expand_path.to_s) == 0
136
132
  Pathname.new(params[:image][:tempfile].path).rename(path)
137
133
  redirect url(:merbiful_admin, :action => "images")
138
134
  end
@@ -146,27 +142,18 @@ module Merbiful
146
142
 
147
143
  def destroy_layout
148
144
  layout = Layout.get(params[:layout_id])
149
- layout.page_versions.each do |page_version|
150
- page_version.layout = nil
151
- page_version.save
152
- end
153
- layout.layout_versions.destroy!
154
145
  layout.destroy
155
146
  redirect url(:merbiful_admin, :action => "layouts")
156
147
  end
157
148
 
158
149
  def destroy_css
159
150
  css = Css.get(params[:css_id])
160
- css.css_nesses.destroy!
161
- css.css_versions.destroy!
162
151
  css.destroy
163
152
  redirect url(:merbiful_admin, :action => "css")
164
153
  end
165
154
 
166
155
  def destroy_js
167
156
  js = Js.get(params[:js_id])
168
- js.js_nesses.destroy!
169
- js.js_versions.destroy!
170
157
  js.destroy
171
158
  redirect url(:merbiful_admin, :action => "js")
172
159
  end
@@ -181,19 +168,19 @@ module Merbiful
181
168
  def create_css
182
169
  new_css = Css.create(:name => next_name(Css))
183
170
  new_css_version = Css::Version.create(:css => new_css)
184
- redirect url(:merbiful_admin, :action => 'css')
171
+ redirect url(:merbiful_admin, :action => 'css', :css_id => new_css.id)
185
172
  end
186
173
 
187
174
  def create_js
188
175
  new_js = Js.create(:name => next_name(Js))
189
176
  new_js_version = Js::Version.create(:js => new_js)
190
- redirect url(:merbiful_admin, :action => 'js')
177
+ redirect url(:merbiful_admin, :action => 'js', :js_id => new_js.id)
191
178
  end
192
179
 
193
180
  def create_layout
194
181
  new_layout = Layout.create(:name => next_name(Layout))
195
182
  new_layout_version = Layout::Version.create(:layout => new_layout)
196
- redirect url(:merbiful_admin, :action => 'layouts')
183
+ redirect url(:merbiful_admin, :action => 'layouts', :layout_id => new_layout.id)
197
184
  end
198
185
 
199
186
  def move_page_up
@@ -1,10 +1,291 @@
1
1
 
2
2
  module Merbiful
3
3
 
4
- class Controller < Merb::Controller
4
+ class Admin < Merb::Controller
5
+
6
+ include RelativeTimeHelpers
7
+
8
+ def index
9
+ render_template_with_layout("index.html.haml")
10
+ end
11
+
12
+ def layouts
13
+ @form_layout = Layout.get(params[:layout_id])
14
+ if request.post?
15
+ @form_layout.update_attributes(params[:layout])
16
+ if @form_layout.valid?
17
+ @form_layout.save
18
+ @form_version = Layout::Version.new(params[:version].merge(:layout => @form_layout))
19
+ if @form_version.valid?
20
+ @form_version.save
21
+ redirect url(:merbiful_admin, :action => "layouts", :layout_id => @form_layout.id)
22
+ end
23
+ end
24
+ else
25
+ if @form_layout
26
+ @form_version = Layout::Version.get(params[:version_id])
27
+ @form_version = @form_layout.latest unless @form_version
28
+ end
29
+ end
30
+ render_template_with_layout("layouts.html.haml")
31
+ end
32
+
33
+ def js
34
+ @form_js = Js.get(params[:js_id])
35
+ if request.post?
36
+ params[:js][:cached] = !!params[:js][:cached]
37
+ @form_js.update_attributes(params[:js])
38
+ if @form_js.valid?
39
+ @form_js.save
40
+ @form_version = Js::Version.new(params[:version].merge(:js => @form_js))
41
+ if @form_version.valid?
42
+ @form_version.save
43
+ redirect url(:merbiful_admin, :action => "js", :js_id => @form_js.id)
44
+ end
45
+ end
46
+ else
47
+ if @form_js
48
+ @form_version = Js::Version.get(params[:version_id])
49
+ @form_version = @form_js.latest unless @form_version
50
+ end
51
+ end
52
+ render_template_with_layout("js.html.haml")
53
+ end
54
+
55
+ def images
56
+ if request.post?
57
+ end
58
+ render_template_with_layout("images.html.haml")
59
+ end
60
+
61
+ def css
62
+ @form_css = Css.get(params[:css_id])
63
+ if request.post?
64
+ params[:css][:cached] = !!params[:css][:cached]
65
+ @form_css.update_attributes(params[:css])
66
+ if @form_css.valid?
67
+ @form_css.save
68
+ @form_version = Css::Version.new(params[:version].merge(:css => @form_css))
69
+ if @form_version.valid?
70
+ @form_version.save
71
+ redirect url(:merbiful_admin, :action => "css", :css_id => @form_css.id)
72
+ end
73
+ end
74
+ else
75
+ if @form_css
76
+ @form_version = Css::Version.get(params[:version_id])
77
+ @form_version = @form_css.latest unless @form_version
78
+ end
79
+ end
80
+ render_template_with_layout("css.html.haml")
81
+ end
82
+
83
+ def pages
84
+ if Page.count == 0
85
+ new_root = Page.create(:path => "/")
86
+ new_root_version = Page::Version.create(:page => new_root, :body => "Here be Dagon")
87
+ end
88
+ @form_page = Page.get(params[:page_id])
89
+ if request.post?
90
+ params[:page][:cached] = !!params[:page][:cached]
91
+ @form_page.update_attributes(params[:page])
92
+ if @form_page.valid?
93
+ @form_page.save
94
+ version_csses = params[:version].delete(:css)
95
+ version_jses = params[:version].delete(:js)
96
+ @form_version = Page::Version.new(params[:version].merge(:page => @form_page))
97
+ version_csses.each do |css|
98
+ @form_version.add_css(Css.get(css))
99
+ end if version_csses
100
+ version_jses.each do |js|
101
+ @form_version.add_js(Js.get(js))
102
+ end if version_jses
103
+ if @form_version.valid?
104
+ @form_version.save
105
+ redirect url(:merbiful_admin, :action => "pages", :page_id => @form_page.id)
106
+ end
107
+ end
108
+ else
109
+ if @form_page
110
+ @form_version = Page::Version.get(params[:version_id])
111
+ @form_version = @form_page.latest unless @form_version
112
+ end
113
+ end
114
+ render_with_layout(Page.all(:parent_id => nil).collect do |page|
115
+ "<ul class='root'>\n#{render_page(page)}\n</ul>"
116
+ end.join("\n"))
117
+ end
118
+
119
+ def render_css
120
+ read_template("admin.css")
121
+ end
122
+
123
+ def destroy_page
124
+ page = Page.get(params[:page_id])
125
+ page.versions.each do |version|
126
+ version.css_nesses.destroy!
127
+ version.js_nesses.destroy!
128
+ version.destroy
129
+ end
130
+ page.destroy
131
+ redirect url(:merbiful_admin, :action => "pages")
132
+ end
133
+
134
+ def upload_image
135
+ path = Pathname.new(File.join(Merb.root, "public", "images", File.basename(params[:image][:filename])))
136
+ Pathname.new(params[:image][:tempfile].path).rename(path)
137
+ redirect url(:merbiful_admin, :action => "images")
138
+ end
139
+
140
+ def delete_image
141
+ path = Pathname.new(File.join(Merb.root, "public", params[:path])).expand_path
142
+ raise "H4xx0r" unless path.to_s.index(Pathname.new(Merb.root).expand_path.to_s) == 0
143
+ path.unlink
144
+ redirect url(:merbiful_admin, :action => "images")
145
+ end
146
+
147
+ def destroy_layout
148
+ layout = Layout.get(params[:layout_id])
149
+ layout.page_versions.each do |page_version|
150
+ page_version.layout = nil
151
+ page_version.save
152
+ end
153
+ layout.layout_versions.destroy!
154
+ layout.destroy
155
+ redirect url(:merbiful_admin, :action => "layouts")
156
+ end
157
+
158
+ def destroy_css
159
+ css = Css.get(params[:css_id])
160
+ css.css_nesses.destroy!
161
+ css.css_versions.destroy!
162
+ css.destroy
163
+ redirect url(:merbiful_admin, :action => "css")
164
+ end
165
+
166
+ def destroy_js
167
+ js = Js.get(params[:js_id])
168
+ js.js_nesses.destroy!
169
+ js.js_versions.destroy!
170
+ js.destroy
171
+ redirect url(:merbiful_admin, :action => "js")
172
+ end
173
+
174
+ def create_page
175
+ parent = Page.get(params[:parent_id])
176
+ new_page = Page.create(:parent => parent, :path => next_path(parent.path))
177
+ new_page_version = Page::Version.create(:page => new_page)
178
+ redirect url(:merbiful_admin, :action => "pages", :page_id => new_page.id)
179
+ end
180
+
181
+ def create_css
182
+ new_css = Css.create(:name => next_name(Css))
183
+ new_css_version = Css::Version.create(:css => new_css)
184
+ redirect url(:merbiful_admin, :action => 'css')
185
+ end
186
+
187
+ def create_js
188
+ new_js = Js.create(:name => next_name(Js))
189
+ new_js_version = Js::Version.create(:js => new_js)
190
+ redirect url(:merbiful_admin, :action => 'js')
191
+ end
192
+
193
+ def create_layout
194
+ new_layout = Layout.create(:name => next_name(Layout))
195
+ new_layout_version = Layout::Version.create(:layout => new_layout)
196
+ redirect url(:merbiful_admin, :action => 'layouts')
197
+ end
198
+
199
+ def move_page_up
200
+ page = Page.get(params[:page_id])
201
+ page.position -= 1
202
+ page.save
203
+ redirect url(:merbiful_admin, :action => "pages")
204
+ end
205
+
206
+ def move_page_down
207
+ page = Page.get(params[:page_id])
208
+ page.position += 1
209
+ page.save
210
+ redirect url(:merbiful_admin, :action => "pages")
211
+ end
212
+
213
+ private
214
+
215
+ def text_area_rows
216
+ 20
217
+ end
218
+
219
+ def next_path(parent_path)
220
+ index = 0
221
+ while Page.first(:path => File.join(parent_path, index.to_s))
222
+ index += 1
223
+ end
224
+ return File.join(parent_path, index.to_s)
225
+ end
226
+
227
+ def next_name(klass)
228
+ index = 0
229
+ while klass.first(:name => index.to_s)
230
+ index += 1
231
+ end
232
+ return index.to_s
233
+ end
234
+
235
+ def errors(obj, meth)
236
+ return ""
237
+ if obj.errors.on(meth)
238
+ obj.errors.on(meth).join(", ")
239
+ else
240
+ ""
241
+ end
242
+ end
243
+
244
+ def render_children(page, ind = "")
245
+ rval = []
246
+ rval << "<ul class='children'>"
247
+ page.children(:order => [:position, :id]).each do |child|
248
+ rval << render_page(child, ind + " ")
249
+ end
250
+ rval << "</ul>"
251
+ return rval.collect do |line| ind + line end.join("\n")
252
+ end
5
253
 
6
- def display(what)
7
- render what.inspect
254
+ def render_page(page, ind = "")
255
+ rval = []
256
+ rval << "<li class='page'>"
257
+ rval << "<ul class='page_info info'>"
258
+ rval << "<a href='#{url(:merbiful_admin, :action => 'pages', :page_id => page.id)}'>"
259
+ rval << "<li class='page_path'>#{page.path}</li>"
260
+ rval << "<li class='page_title'>#{page.title || "untitled"}</li>"
261
+ rval << "<li class='page_version'>ver##{page.latest.id} (#{time_ago_in_words(page.latest.created_at)} ago)</li>"
262
+ rval << "</a>"
263
+ rval << "<li class='up'><a href='#{url(:merbiful_admin, :action => 'move_page_up', :page_id => page.id)}'>&uarr;</a></li>"
264
+ rval << "<li class='down'><a href='#{url(:merbiful_admin, :action => 'move_page_down', :page_id => page.id)}'>&darr;</a></li>"
265
+ rval << "<li class='remove'><a href='#{url(:merbiful_admin, :action => 'destroy_page', :page_id => page.id)}'>-</a></li>" unless page.parent_id.nil?
266
+ rval << "<li class='append'><a href='#{url(:merbiful_admin, :action => 'create_page', :parent_id => page.id)}'>+</a></li>"
267
+ rval << "</ul>"
268
+ rval << render_template_without_layout("page_form.html.haml") if params[:page_id].to_s == page.id.to_s
269
+ rval << render_children(page, ind) unless page.children.empty?
270
+ rval << "</li>"
271
+ return rval.collect do |line| ind + line end.join("\n")
272
+ end
273
+
274
+ def read_template(template)
275
+ Pathname.new(__FILE__).parent.parent.parent.join("templates").join(template).read
276
+ end
277
+
278
+ def render_with_layout(text)
279
+ throw_content :for_layout, text
280
+ ::Haml::Engine.new(read_template("admin_layout.html.haml")).render(self)
281
+ end
282
+
283
+ def render_template_with_layout(template)
284
+ render_with_layout(::Haml::Engine.new(read_template(template)).render(self))
285
+ end
286
+
287
+ def render_template_without_layout(template)
288
+ ::Haml::Engine.new(read_template(template)).render(self)
8
289
  end
9
290
 
10
291
  end
@@ -2,14 +2,35 @@
2
2
  module Merbiful
3
3
 
4
4
  module Body
5
- def to_html(controller)
6
- if self.filter.nil?
7
- self.body
8
- else
9
- filter_class = Merbiful.const_get(self.filter.to_sym)
10
- filter_class.new.render(self.body, controller)
5
+
6
+ def render(controller, caches = {})
7
+ rval = if self.filter.blank?
8
+ self.body
9
+ else
10
+ filter_class = Merbiful.const_get(self.filter.to_sym)
11
+ filter_class.new.render(self.body, controller)
12
+ end
13
+ unless Merb.environment == "development"
14
+ caches.each do |destination, to_cache|
15
+ if to_cache
16
+ path = Pathname.new(File.join(Merb.root, "public", destination))
17
+ Merb.logger.info("Flushing to #{path.inspect}")
18
+ path.parent.mkpath
19
+ path.open("w") do |out|
20
+ out.write(rval)
21
+ end
22
+ end
23
+ end
11
24
  end
25
+ return rval
26
+ end
27
+
28
+ def clear_cache(target)
29
+ return if target == "/"
30
+ path = Pathname.new(File.join(Merb.root, "public", target))
31
+ path.unlink if path.exist?
12
32
  end
33
+
13
34
  end
14
35
 
15
36
  end
@@ -17,9 +17,14 @@ module Merbiful
17
17
  property :updated_at, DateTime
18
18
 
19
19
  has n, :css_nesses, :class_name => "Merbiful::Css::Ness"
20
- has n, :page_versions, :through => :css_nesses, :class_name => "Merbiful::Page::Version"
20
+ has n, :page_versions, :through => :css_nesses, :class_name => "Merbiful::Page::Version", :child_key => [:css_id]
21
21
  has n, :css_versions, :class_name => "Merbiful::Css::Version"
22
22
 
23
+ before :destroy do
24
+ css_nesses.destroy!
25
+ css_versions.destroy!
26
+ end
27
+
23
28
  def latest
24
29
  css_versions.first(:css_id => self.id, :order => [:id.desc])
25
30
  end
@@ -35,9 +40,11 @@ module Merbiful
35
40
  include DataMapper::Validate
36
41
 
37
42
  property :id, Serial
43
+ property :page_version_id, Integer
44
+ property :css_id, Integer
38
45
 
39
- belongs_to :css, :class_name => "Merbiful::Css"
40
- belongs_to :page_version, :class_name => "Merbiful::Page::Version"
46
+ belongs_to :css, :class_name => "Merbiful::Css", :child_key => [:css_id]
47
+ belongs_to :page_version, :class_name => "Merbiful::Page::Version", :child_key => [:page_version_id]
41
48
  end
42
49
 
43
50
  class Version
@@ -21,10 +21,14 @@ module Merbiful
21
21
  has n, :css_versions, :class_name => "Merbiful::Css::Version"
22
22
 
23
23
  def latest
24
- css_versions.first(:order => [:id.desc])
24
+ css_versions.first(:css_id => self.id, :order => [:id.desc])
25
25
  end
26
26
 
27
- def_delegators :latest, :render
27
+ def_delegators :latest, :render, :body, :filter
28
+
29
+ def path
30
+ "/stylesheets/#{latest.id}"
31
+ end
28
32
 
29
33
  class Ness
30
34
  include DataMapper::Resource
@@ -54,6 +58,10 @@ module Merbiful
54
58
 
55
59
  belongs_to :css, :class_name => "Merbiful::Css"
56
60
 
61
+ before :save do
62
+ clear_cache(css.path) if css.latest
63
+ end
64
+
57
65
  end
58
66
 
59
67
  end
@@ -1,11 +1,13 @@
1
1
  module Merbiful
2
2
 
3
- class Eruby
3
+ class Erubis
4
4
 
5
5
  def render(text, scope)
6
- ERB.new(text).result(scope)
6
+ ::Erubis::Eruby.new(text).result(scope.instance_eval do binding end)
7
7
  end
8
8
 
9
9
  end
10
10
 
11
+ FILTERS << Erubis
12
+
11
13
  end
@@ -0,0 +1,14 @@
1
+
2
+ module Merbiful
3
+
4
+ FILTERS = []
5
+
6
+ def self.filters
7
+ FILTERS.inject([[nil, "Verbatim"]]) do |sum, filter|
8
+ filter_name = filter.name.gsub(/^Merbiful::/, "")
9
+ sum + [[filter_name, filter_name]]
10
+ end
11
+ end
12
+
13
+ end
14
+
@@ -3,9 +3,21 @@ module Merbiful
3
3
 
4
4
  class Haml
5
5
 
6
- def render(text)
6
+ def render(text, scope)
7
+ ::Haml::Engine.new(text).render(scope)
7
8
  end
8
9
 
9
10
  end
10
11
 
12
+ class Sass
13
+
14
+ def render(text, scope)
15
+ ::Sass::Engine.new(text).render
16
+ end
17
+
18
+ end
19
+
20
+ FILTERS << Haml
21
+ FILTERS << Sass
22
+
11
23
  end
@@ -0,0 +1,14 @@
1
+
2
+ module Merbiful
3
+
4
+ class ImageHandler
5
+
6
+ IMAGE_REGEXP = /\.(gif|jpg|jpeg|png|bmp)$/
7
+
8
+ def images
9
+
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -16,9 +16,14 @@ module Merbiful
16
16
  property :updated_at, DateTime
17
17
 
18
18
  has n, :js_nesses, :class_name => "Merbiful::Js::Ness"
19
- has n, :page_versions, :through => :js_nesses, :class_name => "Merbiful::Page::Version"
19
+ has n, :page_versions, :through => :js_nesses, :class_name => "Merbiful::Page::Version", :child_key => [:js_id]
20
20
  has n, :js_versions, :class_name => "Merbiful::Js::Version"
21
21
 
22
+ before :destroy do
23
+ js_nesses.destroy!
24
+ js_versions.destroy!
25
+ end
26
+
22
27
  def latest
23
28
  js_versions.first(:js_id => self.id, :order => [:id.desc])
24
29
  end
@@ -34,9 +39,11 @@ module Merbiful
34
39
  include DataMapper::Validate
35
40
 
36
41
  property :id, Serial
42
+ property :page_version_id, Integer
43
+ property :js_id, Integer
37
44
 
38
- belongs_to :js, :class_name => "Merbiful::Js"
39
- belongs_to :page_version, :class_name => "Merbiful::Page::Version"
45
+ belongs_to :js, :class_name => "Merbiful::Js", :child_key => [:js_id]
46
+ belongs_to :page_version, :class_name => "Merbiful::Page::Version", :child_key => [:page_version_id]
40
47
  end
41
48
 
42
49
  class Version
@@ -1,7 +1,7 @@
1
1
 
2
2
  module Merbiful
3
3
 
4
- class Css
4
+ class Js
5
5
 
6
6
  include DataMapper::Resource
7
7
  include DataMapper::Validate
@@ -10,21 +10,24 @@ module Merbiful
10
10
  property :id, Serial
11
11
 
12
12
  property :name, DataMapper::Types::Text, :nullable => false
13
- property :media, DataMapper::Types::Text
14
13
  property :cached, Boolean, :default => true, :nullable => false
15
14
 
16
15
  property :created_at, DateTime
17
16
  property :updated_at, DateTime
18
17
 
19
- has n, :css_nesses, :class_name => "Merbiful::Css::Ness"
20
- has n, :page_versions, :through => :css_nesses, :class_name => "Merbiful::Page::Version"
21
- has n, :css_versions, :class_name => "Merbiful::Css::Version"
18
+ has n, :js_nesses, :class_name => "Merbiful::Js::Ness"
19
+ has n, :page_versions, :through => :js_nesses, :class_name => "Merbiful::Page::Version"
20
+ has n, :js_versions, :class_name => "Merbiful::Js::Version"
22
21
 
23
22
  def latest
24
- css_versions.first(:order => [:id.desc])
23
+ js_versions.first(:js_id => self.id, :order => [:id.desc])
25
24
  end
26
25
 
27
- def_delegators :latest, :render
26
+ def_delegators :latest, :render, :body, :filter
27
+
28
+ def path
29
+ "/javascripts/#{latest.id}"
30
+ end
28
31
 
29
32
  class Ness
30
33
  include DataMapper::Resource
@@ -32,7 +35,7 @@ module Merbiful
32
35
 
33
36
  property :id, Serial
34
37
 
35
- belongs_to :css, :class_name => "Merbiful::Css"
38
+ belongs_to :js, :class_name => "Merbiful::Js"
36
39
  belongs_to :page_version, :class_name => "Merbiful::Page::Version"
37
40
  end
38
41
 
@@ -44,7 +47,7 @@ module Merbiful
44
47
 
45
48
  property :id, Serial
46
49
 
47
- property :css_id, Integer, :index => true, :nullable => false
50
+ property :js_id, Integer, :index => true, :nullable => false
48
51
 
49
52
  property :body, DataMapper::Types::Text
50
53
  property :filter, DataMapper::Types::Text
@@ -52,8 +55,12 @@ module Merbiful
52
55
  property :created_at, DateTime
53
56
  property :updated_at, DateTime
54
57
 
55
- belongs_to :css, :class_name => "Merbiful::Css"
58
+ belongs_to :js, :class_name => "Merbiful::Js"
56
59
 
60
+ before :save do
61
+ clear_cache(js.path) if js.latest
62
+ end
63
+
57
64
  end
58
65
 
59
66
  end
@@ -17,6 +17,14 @@ module Merbiful
17
17
  has n, :layout_versions, :class_name => "Merbiful::Layout::Version"
18
18
  has n, :page_versions, :class_name => "Merbiful::Page::Version"
19
19
 
20
+ before :destroy do
21
+ page_versions.each do |page_version|
22
+ page_version.layout = nil
23
+ page_version.save
24
+ end
25
+ layout_versions.destroy!
26
+ end
27
+
20
28
  def latest
21
29
  layout_versions.first(:layout_id => self.id, :order => [:id.desc])
22
30
  end