0.4.6: The Obligatory ‘Blog’ Demo – Take 2
Friday, April 18th, 2008This post has moved to the wiki @ http://wiki.mackframework.com/index.php/Blog%20Tutorial
This post has moved to the wiki @ http://wiki.mackframework.com/index.php/Blog%20Tutorial
Ok, as you remember a while back we created a simple blog using mack, http://www.mackframework.com/2008/03/04/the-obligatory-blog-demo/. Well now it’s time to add the all important RSS/xml feed to it.
Mack 0.3.0 introduces xml rendering support natively, so this shouldn’t be so hard. First things first, let’s fire up the app, shall we:
$ rake server
Now let’s head over to http://localhost:3000/posts. We should see our beautiful posts index page. Now let’s try to go to http://localhost:3000/posts.xml you should see something that looks like this:

Clearly, that’s not what we want, is it? I didn’t think so. The error is telling us that it’s looking for a file called index.xml.erb in the app/views/posts directory of our blog project. Obviously that file doesn’t exist.
Let’s take a second and talk about why Mack was looking for index.xml.erb. We haven’t changed anything in our controller. Our index method still looks something like this:
def index @posts = Post.find(:all) end
No where in there does it mention xml. The only place xml is mentioned is on the the url itself, remember? We looked for /posts.xml. By adding .xml you’re telling Mack that you want to render, well… xml. So it goes looking for that. That’s also new in 0.3.0. The default is html, but if you append a format (.js, .xml, etc…), it will go looking for app/views/<controller_name>/<action_name>.<format>.erb and render it.
Ok, now that we understand why we’re looking for an xml file, let’s fire up our trusty text editor and create a new file called: app/views/posts/index.xml.erb. Let’s edit the file to look like this:
xml.instruct!ml, :version=>"1.0" xml.rss(:version => "2.0") do xml.channel do xml.title("My Mack Blog") xml.link(posts_index_full_url) xml.description("Find out about all the cool stuff happening on my blog!") xml.language("en-us") xml.copyright("Copyright Me") xml.pubDate(CGI.rfc1123_date(Time.now)) xml.lastBuildDate(CGI.rfc1123_date(Time.now)) @posts.each do |post| xml.entry do xml.title(post.title) xml.link(posts_show_full_url(:id => post.id)) xml.description(post.body) xml.pubDate(post.created_at.strftime("%a, %d %b %Y %H:%M:%S")) end end end end
Mack uses the standard builder gem library. I’m not going to go into explaining how that works, there are plenty of other tutorials and documentation that will show you that. I’m also not going to explain all the necessary pieces of an RSS feed. Instead I’ll point out in that code you’ll see we’re using the @posts instance variable that we set in the index action of our PostsController. Just like regular *.html.erb files we have access to all the instance variables from the controller, as well, helpers, etc…
So now if we go to http://localhost:3000/posts.xml we should see our RSS feed. If we did a view source we should see something that looks like this:
<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <title>My Mack Blog</title> <link>http://localhost:3000/posts</link> <description>Find out about all the cool stuff happening on my blog!</description> <language>en-us</language> <copyright>Copyright Me</copyright>
<pubDate>Tue, 18 Mar 2008 17:18:05 GMT</pubDate> <lastBuildDate>Tue, 18 Mar 2008 17:18:05 GMT</lastBuildDate> <entry> <title>My New Post</title> <link>http://localhost:3000/posts/1</link> <description>This is my first post in my cool Mack blog!</description>
<pubDate>Tue, 18 Mar 2008 11:58:30</pubDate> </entry> </channel> </rss>
Awesome! All that’s really left is create one of those fancy RSS tags in the location field of our browsers that people can click and go straight to the RSS feed. Let’s do that now.
At the top of your app/views/posts/index.html.erb file add the following:
<%= rss_tag(posts_index_url(:format =>ml)) %>
Now, refresh the page in your browser, and there you go, you should now see the little RSS button in the location bar of your browser. If you click that you should be taken to your feed.
That’s all there is to adding not only xml, but an RSS feed to your new blog.
The code for this demo can be found here.
Let’s talk a bit about ‘helpers’ in Mack, shall we?
Those of you familiar with Rails are already familiar with this concepts. In Rails helpers are modules of code that get included into views for certain controllers, or all controllers in the case of ApplicationHelper. These helpers are meant to clean up the views and encapsulate commonly used Ruby code and keep it out of the views. In Rails 2.0 it’s easier now to include some of these helper methods into the controller, but by default, they’re not readily available.
Mack deals with helpers a little differently. Let’s start with ApplicationHelper. In Rails, ApplicationHelper gets included into all the views for every controller. This is extremely useful, and from my experience it’s the most used helper in Rails. The same is true of Mack. Regardless of which controller/view you’re in, ApplicationHelper is there to assist. This brings us to our first difference between Rails and Mack:
* ApplicationHelper is included into both the views AND the controllers.
That’s right, you no longer have to do special voodoo magic to get the contents of ApplicationHelper included into your controller, it’s right there by default, ready to go. Now, I know at this stage you’re saying, if ApplicationHelper is included into all controllers, as well as views, then aren’t the methods in there publicly accessible as actions? The answer is no. Which brings us to our next point on helpers:
* All helper public helper methods are converted to protected methods prior to be included into controllers/views.
By converting all public methods in helpers to protected methods we get around the security concerns regarding the methods becoming publicly available actions in the controllers.
Now, in Rails when you create a controller it creates a new helper module file for that controller. The idea being that you can put helpers into this module that are only available to that controller’s views.
* Mack helpers are NOT controller specific.
Mack, doesn’t do what Rails does in this respect. It’s been my personal experience that these files end up empty and just take up space on my disk. So screw em! We don’t need em.
Ok, so we’ve covered the basics of helpers, let’s talk about a couple of concepts that are available only in the Mack world.
What are controller helpers? In my experience working with Rails I found that I would have ‘helper’ methods, protected or private of course, in my controllers that were meant to assist the actual actions in that controller. Two things eventually dawned on me. The first was that I’m cluttering up my controllers with all these helper methods. The second was that there should be a way to share these amongst other controllers that could probably use them as well. (Example, methods dealing with authentication)
In the Rails world I wrote a gem, controller_helpers, that helps to facilitate this. Well, being as this is the Mack world, this facility is built right in.
If you go and create a module in the app/helpers folder that’s follows the naming convention <controller_name>Helper then it will automatically be included into the appropriate controller. Two things to note here, the security model is still applied, public methods become protected methods. The second is these methods are available in that controller ONLY. They are not available in other controllers or any views within that controller.
class BlogController < Mack::Controller::Base before_filter :authenticate end
module BlogControllerHelper
def authenticate
# do work to authenticate user here...
end
end
As we see the controller name in the previous example was BlogController and it’s helper name was BlogControllerHelper. Now in the example we had an authenticate method in BlogControllerHelper, we realize that we also want to use that in our CommentsController as well. So we can refactor that example to look like this:
class BlogController < Mack::Controller::Base before_filter :authenticate end class CommentsController < Mack::Controller::Base before_filter :authenticate end
module AuthenticationControllerHelper
def authenticate
# do work to authenticate user here...
end
include_safely_into(BlogController, CommentsController)
end
Here you can see in our new AuthenticationControllerHelper module we use the include_safely_into method. This method is documented in the RDoc for Mack, but basically what it does is includes that module into the list of Classes defined, and changes it’s public methods to protected.
Now we have included controller helpers into several different controllers. This helps to keep our controllers limited to just actions, and helps us to reuse code in other places. All very good things.
So, if you’re like me, your Rails ApplicationHelper module is absolutely overflowing with all sorts of bits of code. In one project I have it’s 682 lines of code! Some code does authentication like stuff, is_logged_in?, is_logged_out?, etc… some does formatting, some does other stuff. It’s a big steaming pile of unrelated code.
In Mack you can solve this problem by breaking your code out into Mack::ViewHelpers::<module_name> modules. If you do this then that module is automatically included into all views. Modules in the Mack::ViewHelpers namespace do NOT get included into the controllers. If you want to include them into controllers you can use the include_safely_into method to achieve that goal.
Well, I hope you enjoyed, and are still awake, this brief overview of the way helpers work in Mack. They are different from Rails. I feel these differences are what make Mack helpers really really useful. Mack helpers do more then Rails, and these features can be not only be really powerful, but can really help to keep your code nice and DRY.
Enjoy.
Ok, because every good framework should tell you how to create a blog, why should Mack be any different? Let’s start off with the basics. Is Mack installed? If not, here’s how:
$ sudo gem install mack
Great! Before we move on, make sure that the gem you installed is at LEAST version 0.1.0, otherwise, you’re not going to get very far in this tutorial. Now, let’s move on. Now let’s generate our kick ass new blog, and since we’re going to need some sort of database support for our blog, we’ll configure it to use DataMapper. If you don’t have DataMapper installed, please head over to http://datamapper.org to find out how to install it. Mack has support for ActiveRecord as well, but it’s just easier to get DataMapper going because you don’t have to deal with migrations.
$ mack my_kick_ass_blog -o data_mapper $ cd my_kick_ass_blog
That should’ve created a whole bunch of files and folders for your blog. Now let’s generate some scaffold code for our blog:
$ rake generate:scaffold name=posts
That should’ve created even more files for you. One of those files is app/models/post.rb, let’s open that up, so we can edit it for DataMapper.
Edit the file so it looks something like this:
class Post < DataMapper::Base property :title, :string property :email, :string property :body, :text property :created_at, :datetime property :updated_at, :datetime validates_presence_of :title validates_presence_of :body validates_presence_of :email end
Now, I’m not going to go into detail as to what that’s doing, that’s for the guys at DataMapper to explain. Before we move on to the next step, you’ll probably want to crack open config/database.yml and edit it so it the paths to your database are correct, you’ll probably also want to go to your database system and make sure that the database name you configured in your config/database.yml is created, otherwise this will be a very short trip. I’ll wait while you do that. Finished, great! Let’s move on.
We need to now open a Mack console so we can create the tables needed for our blog.
$ rake console $ Post.table.create! $ exit
Ok, we should now have a posts table in our new database. Isn’t life wonderful? We’re so close to showing the world how wonderful we are as developers.
Now let’s edit our views, so they look something like this:
app/views/posts/index.html.erb:
<h1>Listing posts</h1>
<table>
<tr>
<th>Title</th>
<th>Body</th>
<th>Email</th>
</tr>
<% for post in @posts %>
<tr>
<td><%=post.title %></td>
<td><%=post.body %></td>
<td><%=post.email %></td>
<td><%= link_to("Show", posts_show_url(:id => post.id)) %></td>
<td><%= link_to("Edit", posts_edit_url(:id => post.id)) %></td>
<td><%= link_to("Delete", posts_delete_url(:id => post.id), :method => :delete, :confirm => "Are you sure?") %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to("New Post", posts_new_url) %>
app/views/posts/edit.html.erb:
<h1>Edit post</h1>
<%= error_messages_for :post %>
<form action="<%= posts_update_url(:id => @post.id) %>" class="edit_post" id="edit_post" method="post">
<input type="hidden" name="_method" value="put">
<p>
<b>Title</b><br />
<input id="post_title" name="post[title]" size="30" type="text" value="<%= @post.title %>" />
</p>
<p>
<b>Body</b><br />
<textarea id="post_body" name="post[body]"><%= @post.body %></textarea>
</p>
<p>
<b>Email</b><br />
<input id="post_email" name="post[email]" size="30" type="text" value="<%= @post.email %>" />
</p>
<p>
<input id="post_submit" name="commit" type="submit" value="Create" />
</p>
</form>
<%= link_to("Back", posts_index_url) %>
app/views/posts/show.html.erb:
<p>
<b>Title:</b>
<%= @post.title %>
</p>
<p>
<b>Body:</b>
<%= @post.body %>
</p>
<p>
<b>Email:</b>
<%= @post.email %>
</p>
<p>
<b>Created at:</b>
<%= @post.created_at %>
</p>
<p>
<b>Updated at:</b>
<%= @post.updated_at %>
</p>
<%= link_to("Edit", posts_edit_url(:id => @post.id)) %> |
<%= link_to("Back", posts_index_url) %>
app/views/posts/new.html.erb:
<h1>New post</h1>
<%= error_messages_for :post %>
<form action="<%= posts_create_url %>" class="new_post" id="new_post" method="post">
<p>
<b>Title</b><br />
<input id="post_title" name="post[title]" size="30" type="text" value="<%= @post.title %>" />
</p>
<p>
<b>Body</b><br />
<textarea id="post_body" name="post[body]"><%= @post.body %></textarea>
</p>
<p>
<b>Email</b><br />
<input id="post_email" name="post[email]" size="30" type="text" value="<%= @post.email %>" />
</p>
<p>
<input id="post_submit" name="commit" type="submit" value="Create" />
</p>
</form>
<%= link_to("Back", posts_index_url) %>
Ok, so now we’ve created our forms, and setup our index page. Let’s actually go to the site and see it all works!
First we need to start the server:
$ rake server
Now let’s head on over to http://localhost:3000/posts and see what we’ve got. You should see a page that looks something like this:

Now let’s click on that ‘New Post’ link and fill out the form:

Now, let’s hit that wonderful ‘Create’ button and see what happens!

Congrats! You just created your first blog post! Now let’s head back to http://localhost:3000/posts and see what we’ve got.

Wonderful! Now all that’s left to do is to set our home page to our posts index page. Let’s open up our config/routes.rb and edit the following line:
r.home_page "/", :controller => :default, :action => :index
so that it’s now:
r.home_page "/", :controller => :posts, :action => :index
Now all you have to do is to restart your server and Bob’s your uncle when you hit http://localhost:3000 again you should your fantastic posts index page.
This concludes our brief introductory tutorial on getting going on Mack. Obviously Mack does a lot more, and I highly encourage you to read the RDoc to find out more about what it can do.
Enjoy.
If you would like to add ORM support to your application, it’s simple. Out of the box Mack has support for two popular ORMs, ActiveRecord and DataMapper.Our tests show that DataMapper is 10x slower then ActiveRecord, but who knows, your mileage my vary.
When you create your mack app you can do the following which will add ORM support to your generated app:
$ mack my_cool_mack_app -o activerecord
If you already have a mack app you can very easily add ORM support by adding the following configuration parameter to the default.yml file:
mack::orm: activerecord
And also add a database.yml file to your config directory that looks like this:
development: adapter: mysql database: my_cool_mack_app_development host: localhost username: root password: test: adapter: mysql database: my_cool_mack_app_test host: localhost username: root password: production: adapter: mysql database: my_cool_mack_app_production host: localhost username: root password: