now it's possible to import cms fixtures into database

Oleg committed Nov 08, 2010
commit 494cb98fd1a2012751ed0e8406230b97118ace9e
Showing 9 changed files with 301 additions and 7 deletions
app/models/cms_page.rb +19 -1
@@ @@ -15,7 +15,8 @@ class CmsPage < ActiveRecord::Base
accepts_nested_attributes_for :cms_blocks
# -- Callbacks ------------------------------------------------------------
- before_validation :assign_full_path
+ before_validation :assign_parent,
+ :assign_full_path
after_save :sync_child_pages
# -- Validations ----------------------------------------------------------
@@ @@ -78,6 +79,19 @@ class CmsPage < ActiveRecord::Base
end
# -- Instance Methods -----------------------------------------------------
+ # Transforms existing cms_block information into a hash that can be used
+ # during form processing. That's the only way to modify cms_blocks.
+ def cms_blocks_attributes
+ self.cms_blocks.inject([]) do |arr, block|
+ block_attr = {}
+ block_attr[:type] = block.class.name
+ block_attr[:label] = block.label
+ block_attr[:content] = block.content
+ block_attr[:id] = block.id
+ arr << block_attr
+ end
+ end
+
# Processing content will return rendered content and will populate
# self.cms_tags with instances of CmsTag
def content
@@ @@ -93,6 +107,10 @@ class CmsPage < ActiveRecord::Base
protected
+ def assign_parent
+ self.parent ||= CmsPage.root unless self == CmsPage.root || CmsPage.count == 0
+ end
+
def assign_full_path
self.full_path = self.parent ? "#{self.parent.full_path}/#{self.slug}".squeeze('/') : '/'
end
app/models/cms_snippet.rb +21 -5
@@ @@ -19,11 +19,7 @@ class CmsSnippet < ActiveRecord::Base
end
def self.initialize_or_find(cms_page, slug)
- if ComfortableMexicanSofa.configuration.seed_data_path
- CmsTag::Snippet.load_from_file(cms_page.cms_site, slug)
- else
- find_by_slug(slug)
- end || new(:slug => slug)
+ load_for_slug(cms_page.cms_site, slug) || new(:slug => slug)
end
# Attempting to initialize snippet object from yaml file that is found in config.seed_data_path
@@ @@ -35,4 +31,24 @@ class CmsSnippet < ActiveRecord::Base
new(attributes)
end
+ # Wrapper around load_from_file and find_by_slug
+ # returns layout object if loaded / found
+ def self.load_for_slug!(site, slug)
+ if ComfortableMexicanSofa.configuration.seed_data_path
+ load_from_file(site, slug)
+ else
+ # FIX: This a bit odd... Snippet is used as a tag, so sometimes there's no site scope
+ # being passed. So we're enforcing this only if it's found. Need to review.
+ conditions = site ? {:conditions => {:cms_site_id => site.id}} : {}
+ find_by_slug(slug, conditions)
+ end || raise(ActiveRecord::RecordNotFound, "CmsSnippet with slug: #{slug} cannot be found")
+ end
+
+ # Non-blowing-up version of the method above
+ def self.load_for_slug(site, slug)
+ load_for_slug!(site, slug)
+ rescue ActiveRecord::RecordNotFound
+ nil
+ end
+
end
tasks/comfortable_mexican_sofa.rake b/lib/tasks/comfortable_mexican_sofa.rake +157 -0
@@ @@ -0,0 +1,157 @@
+ namespace :comfortable_mexican_sofa do
+
+ namespace :import do
+
+ task :check_for_requirements => :environment do |task, args|
+ if !(@seed_path = ComfortableMexicanSofa.config.seed_data_path)
+ abort('ComfortableMexicanSofa.config.seed_data_path is not set. Where are those yaml files?')
+ end
+ if !(@site = CmsSite.find_by_hostname(args[:hostname]))
+ abort("Can't find site with HOSTNAME '#{args[:site]}'")
+ end
+ puts "Starting import into #{@site.label} (#{@site.hostname})..."
+ end
+
+ desc 'Import layouts into database'
+ task :layouts => [:environment, :check_for_requirements] do |task, args|
+ puts 'Importing Layouts...'
+ layouts = Dir.glob(File.expand_path("#{@site.hostname}/layouts/**/*.yml", @seed_path)).collect do |layout_file_path|
+ attributes = YAML.load_file(layout_file_path).symbolize_keys!
+ @site.cms_layouts.load_for_slug!(@site, attributes[:slug])
+ end
+
+ CmsPage.connection.transaction do
+ # Fixtures are not ordered in any particular way. Saving order matters,
+ # so we cycle them until there nothing left to save
+ while layouts.present?
+ layout = layouts.shift
+ if !layout.parent || layout.parent && parent = @site.cms_layouts.find_by_slug(layout.parent.slug)
+ layout.parent = (parent rescue nil)
+ should_write = true
+ existing_layout = nil
+
+ if existing_layout = @site.cms_layouts.find_by_slug(layout.slug)
+ print "Found layout in database with slug: #{layout.slug}. Overwrite? (yN): "
+ should_write = ($stdin.gets.to_s.strip.downcase == 'y')
+ end
+ if should_write
+ if existing_layout
+ existing_layout.attributes = layout.attributes.slice('label', 'content', 'css', 'js')
+ layout = existing_layout
+ end
+ layout.save!
+ puts "Saved layout: #{layout.label} (#{layout.slug})"
+ else
+ puts "Skipping layout: #{layout.label} (#{layout.slug})"
+ end
+ else
+ layouts.push layout
+ end
+ end
+ end
+ end
+
+ desc 'Import pages into database'
+ task :pages => [:environment, :check_for_requirements] do |task, args|
+ puts 'Importing Pages...'
+ pages = Dir.glob(File.expand_path("#{@site.hostname}/pages/**/*.yml", @seed_path)).collect do |page_file_path|
+ attributes = YAML.load_file(page_file_path).symbolize_keys!
+ @site.cms_pages.load_for_full_path!(@site, attributes[:full_path])
+ end
+ CmsPage.connection.transaction do
+ # Fixtures are not ordered in any particular way. Saving order matters,
+ # so we cycle them until there nothing left to save
+ while pages.present?
+ page = pages.shift
+ if !page.parent || page.parent && parent = @site.cms_pages.find_by_full_path(page.parent.full_path)
+ page.parent = (parent rescue nil)
+ page.cms_layout = @site.cms_layouts.find_by_slug(page.cms_layout.slug)
+ should_write = true
+ existing_page = nil
+
+ if existing_page = @site.cms_pages.find_by_full_path(page.full_path)
+ print "Found page in database with full_path: #{page.full_path}. Overwrite? (yN): "
+ should_write = ($stdin.gets.to_s.strip.downcase == 'y')
+ end
+
+ if should_write
+ if existing_page
+ # merging cms_blocks_attributes with the existing page
+ attrs = page.cms_blocks_attributes.collect do |block_attrs|
+ existing_block = existing_page.cms_blocks_attributes.find{|b| b[:label] == block_attrs[:label]}
+ block_attrs[:id] = existing_block[:id] if existing_block
+ block_attrs.stringify_keys
+ end
+
+ existing_page.attributes = page.attributes.slice('label')
+ existing_page.cms_blocks_attributes = attrs
+ page = existing_page
+ end
+ page.save!
+ puts "Saved page: #{page.label} (#{page.full_path})"
+ else
+ puts "Skipping page: #{page.label} (#{page.full_path})"
+ end
+ else
+ pages.push page
+ end
+ end
+ end
+ end
+
+ desc 'Import snippets into database'
+ task :snippets => [:environment, :check_for_requirements] do |task, args|
+ puts 'Importing Snippets...'
+ snippets = Dir.glob(File.expand_path("#{@site.hostname}/snippets/**/*.yml", @seed_path)).collect do |snippet_file_path|
+ attributes = YAML.load_file(snippet_file_path).symbolize_keys!
+ @site.cms_snippets.load_for_slug!(@site, attributes[:slug])
+ end
+ CmsSnippet.connection.transaction do
+ snippets.each do |snippet|
+ should_write = true
+ existing_snippet = nil
+ if existing_snippet = @site.cms_snippets.find_by_slug(snippet.slug)
+ print "Found snippet in database with slug: #{snippet.slug}. Overwrite? (yN): "
+ should_write = ($stdin.gets.to_s.strip.downcase == 'y')
+ end
+ if should_write
+ if existing_snippet
+ existing_snippet.attributes = snippet.attributes.slice('label', 'content')
+ snippet = existing_snippet
+ end
+ snippet.save!
+ puts "Saved snippet: #{snippet.label} (#{snippet.slug})"
+ else
+ puts "Skipping snippet: #{snippet.label} (#{snippet.slug})"
+ end
+ end
+ end
+ end
+
+ desc 'Import layouts, pages and snippets all in one go'
+ task :all => [:layouts, :pages, :snippets]
+
+ end
+
+ namespace :export do
+
+ desc 'Export layouts to yaml files'
+ task :layouts => [:environment, :check_for_requirements] do |task, args|
+
+ end
+
+ desc 'Export pages to yaml files'
+ task :pages => [:environment, :check_for_requirements] do |task, args|
+
+ end
+
+ desc 'Export snippets to yaml files'
+ task :snippets => [:environment, :check_for_requirements] do |task, args|
+
+ end
+
+ desc 'Export layouts, pages and snippets all in one go'
+ task :all => [:layouts, :pages, :snippets]
+
+ end
+ end
\ No newline at end of file
test/cms_seeds/test.host/pages/child.yml +1 -0
@@ @@ -1,6 +1,7 @@
label: Child Page
parent: /
cms_layout: default
+ full_path: /child
slug: child
cms_blocks_attributes:
-
test/cms_seeds/test.host/pages/child/subchild.yml +1 -0
@@ @@ -1,6 +1,7 @@
label: Child Page
parent: /child
cms_layout: nested
+ full_path: /child/subchild
slug: subchild
cms_blocks_attributes:
-
test/cms_seeds/test.host/pages/index.yml +2 -1
@@ @@ -1,7 +1,8 @@
label: Default Page
parent:
cms_layout: default
- slug:
+ full_path: /
+ slug:
cms_blocks_attributes:
-
label: content
test/integration/rake_tasks_test.rb +59 -0
@@ @@ -0,0 +1,59 @@
+ require File.dirname(__FILE__) + '/../test_helper'
+
+ require 'rake'
+ require 'rake/rdoctask'
+ require 'rake/testtask'
+
+ Rake.application.rake_require '../lib/tasks/comfortable_mexican_sofa'
+
+ class RakeTasksTest < ActionDispatch::IntegrationTest
+
+ def test_layouts_import
+ CmsLayout.destroy_all
+ ComfortableMexicanSofa.configuration.seed_data_path = File.expand_path('../cms_seeds', File.dirname(__FILE__))
+
+ assert_difference 'CmsLayout.count', 2 do
+ capture_rake_output{
+ Rake.application['comfortable_mexican_sofa:import:check_for_requirements'].execute(:hostname => 'test.host')
+ Rake.application['comfortable_mexican_sofa:import:layouts'].execute(:hostname => 'test.host')
+ }
+ end
+ end
+
+ def test_pages_import
+ CmsPage.destroy_all
+ ComfortableMexicanSofa.configuration.seed_data_path = File.expand_path('../cms_seeds', File.dirname(__FILE__))
+
+ assert_difference ['CmsPage.count', 'CmsBlock.count'], 3 do
+ capture_rake_output{
+ Rake.application['comfortable_mexican_sofa:import:check_for_requirements'].execute(:hostname => 'test.host')
+ Rake.application['comfortable_mexican_sofa:import:pages'].execute(:hostname => 'test.host')
+ }
+ end
+ end
+
+ def test_snippets_import
+ CmsSnippet.destroy_all
+ ComfortableMexicanSofa.configuration.seed_data_path = File.expand_path('../cms_seeds', File.dirname(__FILE__))
+
+ assert_difference 'CmsSnippet.count', 1 do
+ capture_rake_output{
+ Rake.application['comfortable_mexican_sofa:import:check_for_requirements'].execute(:hostname => 'test.host')
+ Rake.application['comfortable_mexican_sofa:import:snippets'].execute(:hostname => 'test.host')
+ }
+ end
+ end
+
+ protected
+
+ def capture_rake_output
+ s = StringIO.new
+ oldstdout = $stdout
+ $stdout = s
+ yield
+ s.string
+ ensure
+ $stdout = oldstdout
+ end
+
+ end
\ No newline at end of file
test/unit/cms_page_test.rb +16 -0
@@ @@ -15,6 +15,13 @@ class CmsPageTest < ActiveSupport::TestCase
assert_has_errors_on page, [:cms_layout, :slug, :label]
end
+ def test_validation_of_parent_presence
+ page = cms_sites(:default).cms_pages.new(new_params)
+ assert !page.parent
+ assert page.valid?, page.errors.full_messages
+ assert_equal cms_pages(:default), page.parent
+ end
+
def test_validation_of_parent_relationship
page = cms_pages(:default)
assert !page.parent
@@ @@ -174,6 +181,15 @@ class CmsPageTest < ActiveSupport::TestCase
assert !CmsPage.load_for_full_path(cms_sites(:default), '/invalid_page')
end
+ def test_cms_blocks_attributes_accessor
+ page = cms_pages(:default)
+ assert_equal page.cms_blocks.count, page.cms_blocks_attributes.size
+ assert_equal 'CmsTag::FieldText', page.cms_blocks_attributes.first[:type]
+ assert_equal 'default_field_text', page.cms_blocks_attributes.first[:label]
+ assert_equal 'default_field_text_content', page.cms_blocks_attributes.first[:content]
+ assert page.cms_blocks_attributes.first[:id]
+ end
+
protected
def new_params(options = {})
test/unit/cms_snippet_test.rb +25 -0
@@ @@ -32,4 +32,29 @@ class CmsSnippetTest < ActiveSupport::TestCase
assert_equal 'Content for Default Snippet', snippet.content
end
+ def test_load_for_slug
+ assert snippet = CmsSnippet.load_for_slug!(cms_sites(:default), 'default')
+ assert !snippet.new_record?
+ db_content = snippet.content
+
+ ComfortableMexicanSofa.configuration.seed_data_path = File.expand_path('../cms_seeds', File.dirname(__FILE__))
+ assert snippet = CmsSnippet.load_for_slug!(cms_sites(:default), 'default')
+ assert snippet.new_record?
+ file_content = snippet.content
+ assert_not_equal db_content, file_content
+ end
+
+ def test_load_for_slug_exceptions
+ assert_exception_raised ActiveRecord::RecordNotFound, 'CmsSnippet with slug: not_found cannot be found' do
+ CmsSnippet.load_for_slug!(cms_sites(:default), 'not_found')
+ end
+ assert !CmsSnippet.load_for_slug(cms_sites(:default), 'not_found')
+
+ ComfortableMexicanSofa.configuration.seed_data_path = File.expand_path('../cms_seeds', File.dirname(__FILE__))
+ assert_exception_raised ActiveRecord::RecordNotFound, 'CmsSnippet with slug: not_found cannot be found' do
+ CmsSnippet.load_for_slug!(cms_sites(:default), 'not_found')
+ end
+ assert !CmsSnippet.load_for_slug(cms_sites(:default), 'not_found')
+ end
+
end