I’m currently working on a new home for the Podcast I’m co-hosting. Since I won’t be the only one posting on the page, Octopress isn’t really a choice. So I’m going with with Rails. The design is almost completely made with Twitter Bootstrap, Since design isn’t my strong suit, and I’m using ActiveAdmin for the admin interface.1 I’m thinking about making the finished app available for others, but at the moment I’m not really sure how exactly that will be. More about that in the future.

One of the troublesome things when moving a page is taking all the existing data with you. Our current side is running on Wordpress, which allows you to export your posts and pages as XML. In this post I’ll explain how we will put two little forms in the admin interface with which we can choose a file to import from, parse the XML and create our pages or episodes. In the next post we’ll see, if we can’t improve the parsing a bit.

Page Import

Let’s start with the page import.

To parse the XML we’ll use Nokogiri, which we need to add to our Gemfile:

gem 'nokogiri'

And run bundle install.

Then we’ll create the partial app/views/admin/_import.html.erb with the form we’ll use to initiate the import. The form should call the import_xml action, which we’ll write later, and should allow us to submit a file. Since Formtastic is already installed for ActiveAdmin, we might as well use it:

<%= semantic_form_for :import, :url => { :action => "import_xml" } do |f| %>
  <%= f.input :file, :as => :file, :label => false %>
    <%= f.actions do %>
    <%= f.action :submit, :as => :button %>
  <% end %>
<% end  %>

Then we render the partial in a sidebar on our pages admin index2:

sidebar "Import", :only => :index do
  simple_format("Import pages from a XML file.") + render("admin/import")
end

And now we need to write the action. The XML for your exported pages (or posts) you get from Wordpress looks something like this:

<channel>
  <!-- Some stuff -->

  <item>
    <title>Impressum</title>
    <link>http://www.talesofinterest.de/impressum/</link>
    <pubDate>Wed, 22 Sep 2010 14:16:25 +0000</pubDate>
    <dc:creator>code-chimp</dc:creator>
    <guid isPermaLink="false">http://www.talesofinterest.de/</guid>
    <description></description>
    <content:encoded>A bunch of Important stuff</content:encoded>
    <!-- Some meta stuff -->
  </item>

  <!-- Some more items -->
</channel>

What we need to do is take the title and content:encoded of every item, create a new page with it and redirect to the pages admin index. In our app/admin/pages.rb we do the following:

collection_action :import_xml, :method => :post do
  items = Nokogiri::XML(params[:import][:file]).xpath("//channel//item")
  items.each do |item|
    Page.create!(:title => item.at_xpath("title").text, :content => item.at_xpath("content:encoded").text)
  end
  redirect_to admin_pages_path, :notice => "Pages imported successfully!"
end

That’s it for our page import.

Episode Import

If you have only one podcast and modelled your episodes like a blog post, it’s actually pretty straightforward, too.

We’ll be using the same partial but change the import_xml a bit, so that the created_at stamp of our episodes equals the pubDate. Let’s do that in our app/admin/episodes.rb:

sidebar "Import", :only => :index do
  simple_format("Import episodes from a XML file.") + render("admin/import")
end
collection_action :import_xml, :method => :post do
  items = Nokogiri::XML(params[:import][:file]).xpath("//channel//item")
  items.each do |item|
    Episode.create!(:title => item.at_xpath("title").text,
      :description => item.at_xpath("content:encoded").text,
      :created_at => item.at_xpath("pubDate").text)
    end
  redirect_to admin_podcasts_path, :notice => "Episodes imported successfully!"
end

That is all.

In the following post I will show you, how the episode import could look like, if you app is structured a bit more complex.


  1. Mainly because I used it a ton at work. RailsAdmin does look really cool, too. ↩︎

  2. Note that it won’t actually work yet. It will return an error because we haven’t written the import_xml action yet. ↩︎