{"id":51808,"date":"2009-02-11T20:27:00","date_gmt":"2009-02-11T20:27:00","guid":{"rendered":"\/2009\/04\/02\/blog-plugin-tutorial-for-ruby-on-rails"},"modified":"2009-08-30T00:37:50","modified_gmt":"2009-08-30T00:37:50","slug":"blog-plugin-tutorial-for-ruby-on-rails","status":"publish","type":"post","link":"http:\/\/pullmonkey.com\/2009\/02\/11\/blog-plugin-tutorial-for-ruby-on-rails\/","title":{"rendered":"Blog plugin tutorial for Ruby on Rails"},"content":{"rendered":"

Update:<\/b> Bloggity does not require the Engines plugin to run if you are using Rails 2.3 or above (where the Engines plugin is baked in). -- Noted below by Bill.
\n
Update:<\/b> Added the plugin to github - simple_blog<\/a>. It is not production ready or really all that usable quite yet.<\/p>\n

Ok, so this a rant and I am sorry for that - but as simple as it is, I have been looking for a blog plugin lately. The problem with the plugins I find is that I don't want to have to deal with the engines plugin or have the controllers, models, views, etc ... all extracted into my applications code. I want it all external (hence a plugin) but let it be minimally configurable.<\/p>\n

So in my recent search for a blog plugin for rails, I came across two that look very useful, but each with their flaws:
\n1)
bloget<\/a> - Everything is extracted to my code space. Why? Yes, I realize that it is most likely because I will want to override things, but get out of my space and keep to yourself! \ud83d\ude42
\nProvide me a way to override things that I would need to (there really shouldn't be too many), after all it is ruby.
\n2)
bloggity<\/a> - Uses the engines plugin! I have nothing against the engines plugin (I think it is well written and documented) but for a freaking blog plugin?!? Why? <\/p>\n

Is there a third option?
\nGlad you asked - yes, there is a third option - I hate to say it, but do it right! There's your third option.
\nOk, but really, if there is a third option (a third plugin), I would love to hear about it.<\/p>\n

Ok, so all that to lead up to a little plugin tutorial? Well, it got your attention didn't it?<\/p>\n

Starting from scratch<\/h1>\n

Ok, I guess I will start from scratch. So let's get started.<\/p>\n

Creating a plugin<\/h2>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt>7\r\n<\/tt>8\r\n<\/tt>9\r\n<\/tt>10<\/strong>\r\n<\/tt>11\r\n<\/tt>12\r\n<\/tt>13\r\n<\/tt>14\r\n<\/tt><\/pre>\n<\/td>\n
\n
pullmonkey$<\/span> .\/script\/generate plugin simple_blog\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/lib\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/tasks\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/test\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/README<\/span>\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/MIT<\/span>-LICENSE<\/span>\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/Rakefile<\/span>\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/init.rb\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/install.rb\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/uninstall.rb\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/lib\/simple_blog.rb\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/tasks\/simple_blog_tasks.rake\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/test\/simple_blog_test.rb\r\n<\/tt>      create  vendor\/plugins\/simple_blog\/test\/test_helper.rb\r\n<\/tt><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Create the app directories for your plugin<\/h2>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt>7\r\n<\/tt>8\r\n<\/tt>9\r\n<\/tt>10<\/strong>\r\n<\/tt><\/pre>\n<\/td>\n
\n
pullmonkey$<\/span> cd vendor\/plugins\/simple_blog\/  # pretty important<\/span>\r\n<\/tt>pullmonkey$<\/span> ls\r\n<\/tt>init.rb  install.rb  lib  MIT<\/span>-LICENSE<\/span>  Rakefile<\/span>  README<\/span>  tasks  test  uninstall.rb\r\n<\/tt>pullmonkey$<\/span> mkdir app\r\n<\/tt>pullmonkey$<\/span> mkdir -p app\/models\r\n<\/tt>pullmonkey$<\/span> mkdir -p app\/controllers\r\n<\/tt>pullmonkey$<\/span> mkdir -p app\/views\r\n<\/tt>pullmonkey$<\/span> mkdir -p app\/helpers\r\n<\/tt>pullmonkey$<\/span> ls app\/\r\n<\/tt>controllers  helpers  models  views\r\n<\/tt><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Well that was easy, so let's move on.<\/p>\n

<\/p>\n

Models, Views, Controllers and Helpers - Living as one in my plugin<\/h1>\n

Models<\/h2>\n

Ok, so we have a clear path for where our models, controllers, views, and helpers should live, right?
\nFor simplicity, let's just have a post and comment model - you have all seen this a billion times.<\/p>\n

Models: vendor\/plugins\/simple_blog\/app\/models\/post.rb<\/h3>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt><\/pre>\n<\/td>\n
\n
class<\/span> Post<\/span> < ActiveRecord<\/span>::Base<\/span>\r\n<\/tt>  has_many :comments<\/span>\r\n<\/tt>end<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Models: vendor\/plugins\/simple_blog\/app\/models\/comment.rb<\/h3>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt><\/pre>\n<\/td>\n
\n
class<\/span> Comment<\/span> < ActiveRecord<\/span>::Base<\/span>\r\n<\/tt>  belongs_to :post<\/span>\r\n<\/tt>end<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

And there you have it.
\nSo what do you do to tell your rails application about your models?
\nSimple - inside vendor\/plugins\/simple_blog\/init.rb - add these lines<\/p>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt><\/pre>\n<\/td>\n
\n
model_path = File<\/span>.join(directory, '<\/span>app<\/span>'<\/span><\/span>, '<\/span>models<\/span>'<\/span><\/span>)\r\n<\/tt>$LOAD_PATH<\/span> << model_path\r\n<\/tt>ActiveSupport<\/span>::Dependencies<\/span>.load_paths << model_path<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Ok, so let's test it out.<\/h3>\n

Step 1 - we will need some default migrations for the model to use.
\nPost migration:<\/p>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt>7\r\n<\/tt>8\r\n<\/tt>9\r\n<\/tt>10<\/strong>\r\n<\/tt>11\r\n<\/tt>12\r\n<\/tt>13\r\n<\/tt>14\r\n<\/tt>15<\/strong>\r\n<\/tt><\/pre>\n<\/td>\n
\n
pullmonkey$<\/span> .\/script\/generate migration post\r\n<\/tt># This is what mine looks like<\/span>\r\n<\/tt>class<\/span> Post<\/span> < ActiveRecord<\/span>::Migration<\/span>\r\n<\/tt>  def<\/span> self<\/span>.up\r\n<\/tt>    create_table :posts<\/span> do<\/span> |t|\r\n<\/tt>      t.string :subject<\/span>\r\n<\/tt>      t.text   :body<\/span>\r\n<\/tt>      t.timestamps\r\n<\/tt>    end<\/span>\r\n<\/tt>  end<\/span>\r\n<\/tt>\r\n<\/tt>  def<\/span> self<\/span>.down\r\n<\/tt>    drop_table :posts<\/span>\r\n<\/tt>  end<\/span>\r\n<\/tt>end<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

And then the comment migration:<\/p>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt>7\r\n<\/tt>8\r\n<\/tt>9\r\n<\/tt>10<\/strong>\r\n<\/tt>11\r\n<\/tt>12\r\n<\/tt>13\r\n<\/tt>14\r\n<\/tt><\/pre>\n<\/td>\n
\n
pullmonkey$<\/span> .\/script\/generate migration comment\r\n<\/tt># This is what mine looks like<\/span>\r\n<\/tt>  def<\/span> self<\/span>.up\r\n<\/tt>    create_table :comments<\/span> do<\/span> |t|\r\n<\/tt>      t.string :username<\/span>\r\n<\/tt>      t.text   :body<\/span>\r\n<\/tt>      t.references :post<\/span>\r\n<\/tt>      t.timestamps\r\n<\/tt>    end<\/span>\r\n<\/tt>  end<\/span>\r\n<\/tt>\r\n<\/tt>  def<\/span> self<\/span>.down\r\n<\/tt>    drop_table :comments<\/span>\r\n<\/tt>  end<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Run the migrations:<\/p>\n\n\n
\n
\r\n<\/tt><\/pre>\n<\/td>\n
\n
pullmonkey$<\/span> rake db:migrate<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

That was all just setup - now for the actual testing:<\/p>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt>7\r\n<\/tt>8\r\n<\/tt>9\r\n<\/tt>10<\/strong>\r\n<\/tt>11\r\n<\/tt>12\r\n<\/tt>13\r\n<\/tt>14\r\n<\/tt>15<\/strong>\r\n<\/tt>16\r\n<\/tt>17\r\n<\/tt>18\r\n<\/tt>19\r\n<\/tt>20<\/strong>\r\n<\/tt>21\r\n<\/tt>22\r\n<\/tt>23\r\n<\/tt>24\r\n<\/tt><\/pre>\n<\/td>\n
\n
pullmonkey$<\/span> .\/script\/console\r\n<\/tt>Loading<\/span> development environment (Rails<\/span> 2.2<\/span>.2<\/span>)\r\n<\/tt>>> Comment<\/span>.new\r\n<\/tt>=> #<Comment id: nil, username: nil, body: nil, post_id: nil, created_at: nil, updated_at: nil><\/span>\r\n<\/tt>>> Post<\/span>.new\r\n<\/tt>=> #<Post id: nil, subject: nil, body: nil, created_at: nil, updated_at: nil><\/span>\r\n<\/tt>>> p = Post<\/span>.create(:subject<\/span> => "<\/span>Test 1<\/span>"<\/span><\/span>, :body<\/span> => "<\/span>My Body<\/span>"<\/span><\/span>)\r\n<\/tt>=> #<Post id: 1, subject: "Test 1", body: "My Body", created_at: "2009-02-11 19:09:25", updated_at: "2009-02-11 19:09:25"><\/span>\r\n<\/tt>>> p.body\r\n<\/tt>=> "<\/span>My Body<\/span>"<\/span><\/span>\r\n<\/tt>>> p.subject\r\n<\/tt>=> "<\/span>Test 1<\/span>"<\/span><\/span>\r\n<\/tt>>> p.new_record?\r\n<\/tt>=> false<\/span>\r\n<\/tt>>> p.comments\r\n<\/tt>=> []\r\n<\/tt>>> c = Comment<\/span>.create(:username<\/span> => '<\/span>pullmonkey<\/span>'<\/span><\/span>, :body<\/span> => "<\/span>this is simple<\/span>"<\/span><\/span>)\r\n<\/tt>=> #<Comment id: 1, username: "pullmonkey", body: "this is simple", post_id: nil, created_at: "2009-02-11 19:10:01", updated_at: "2009-02-11 19:10:01"><\/span>\r\n<\/tt>>> p.comments << c\r\n<\/tt>=> [#<Comment id: 1, username: "pullmonkey", body: "this is simple", post_id: 1, created_at: "2009-02-11 19:10:01", updated_at: "2009-02-11 19:10:06">]<\/span>\r\n<\/tt>>> p.comments\r\n<\/tt>=> [#<Comment id: 1, username: "pullmonkey", body: "this is simple", post_id: 1, created_at: "2009-02-11 19:10:01", updated_at: "2009-02-11 19:10:06">]<\/span>\r\n<\/tt>>> Post<\/span>.first.comments\r\n<\/tt>=> [#<Comment id: 1, username: "pullmonkey", body: "this is simple", post_id: 1, created_at: "2009-02-11 19:10:01", updated_at: "2009-02-11 19:10:06">]<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

That's probably good enough. We have a working model and relationships. The best part is that all the code is still in the plugin.
\nWhat does my code space contain?<\/p>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt>7\r\n<\/tt>8\r\n<\/tt>9\r\n<\/tt>10<\/strong>\r\n<\/tt>11\r\n<\/tt>12\r\n<\/tt>13\r\n<\/tt>14\r\n<\/tt>15<\/strong>\r\n<\/tt><\/pre>\n<\/td>\n
\n
pullmonkey$<\/span> ls -l app\/**\r\n<\/tt>app\/controllers:\r\n<\/tt>total 4<\/span>\r\n<\/tt>-rw-rw-r--  1<\/span> pullmonkey pullmonkey 720<\/span> Feb<\/span> 11<\/span> 11<\/span>:00<\/span> application.rb\r\n<\/tt>\r\n<\/tt>app\/helpers:\r\n<\/tt>total 4<\/span>\r\n<\/tt>-rw-rw-r--  1<\/span> pullmonkey pullmonkey 115<\/span> Feb<\/span> 11<\/span> 11<\/span>:00<\/span> application_helper.rb\r\n<\/tt>\r\n<\/tt>app\/models:\r\n<\/tt>total 0<\/span>\r\n<\/tt>\r\n<\/tt>app\/views:\r\n<\/tt>total 4<\/span>\r\n<\/tt>drwxrwxr-x  2<\/span> pullmonkey pullmonkey 4096<\/span> Feb<\/span> 11<\/span> 11<\/span>:00<\/span> layouts<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

\nJust the defaults - neat \ud83d\ude42<\/p>\n

Controllers<\/h2>\n

In much the same way as models, we can easily use controllers from our plugin. No extracting, no engines plugin.<\/p>\n

Controllers: vendor\/plugins\/simple_blog\/app\/controllers\/posts_controller.rb<\/h3>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt>7\r\n<\/tt>8\r\n<\/tt>9\r\n<\/tt>10<\/strong>\r\n<\/tt>11\r\n<\/tt>12\r\n<\/tt>13\r\n<\/tt>14\r\n<\/tt>15<\/strong>\r\n<\/tt>16\r\n<\/tt>17\r\n<\/tt>18\r\n<\/tt>19\r\n<\/tt>20<\/strong>\r\n<\/tt>21\r\n<\/tt>22\r\n<\/tt>23\r\n<\/tt>24\r\n<\/tt><\/pre>\n<\/td>\n
\n
class<\/span> PostsController<\/span> < ApplicationController<\/span>\r\n<\/tt>  def<\/span> index<\/span>\r\n<\/tt>    @posts<\/span> = Post<\/span>.all\r\n<\/tt>  end<\/span>\r\n<\/tt>\r\n<\/tt>  def<\/span> show<\/span>\r\n<\/tt>    @post<\/span> = Post<\/span>.find(params[:id<\/span>])\r\n<\/tt>  end<\/span>\r\n<\/tt>\r\n<\/tt>  def<\/span> new<\/span>\r\n<\/tt>    @post<\/span> = Post<\/span>.new\r\n<\/tt>  end<\/span>\r\n<\/tt>\r\n<\/tt>  def<\/span> create<\/span>\r\n<\/tt>    if<\/span> @post<\/span> = Post<\/span>.create(params[:post<\/span>])\r\n<\/tt>      flash[:notice<\/span>] = "<\/span>Post Created<\/span>"<\/span><\/span>\r\n<\/tt>      redirect_to :action<\/span> => '<\/span>index<\/span>'<\/span><\/span>\r\n<\/tt>    else<\/span>\r\n<\/tt>      flash[:error<\/span>] = "<\/span>Post Not Created<\/span>"<\/span><\/span>\r\n<\/tt>      render :action<\/span> => '<\/span>new<\/span>'<\/span><\/span>\r\n<\/tt>    end<\/span>\r\n<\/tt>  end<\/span>\r\n<\/tt>  #.... more code<\/span>\r\n<\/tt>end<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Controllers: vendor\/plugins\/simple_blog\/app\/controllers\/comments_controller.rb<\/h3>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt><\/pre>\n<\/td>\n
\n
class<\/span> CommentsController<\/span> < ApplicationController<\/span>\r\n<\/tt>  def<\/span> index<\/span>\r\n<\/tt>    @comments<\/span> = Comment<\/span>.find_all_by_post_id(params[:post_id<\/span>])\r\n<\/tt>  end<\/span>\r\n<\/tt>  #.... more code<\/span>\r\n<\/tt>end<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Now, to register the controllers, add the following to vendor\/plugins\/simple_blog\/init.rb:<\/p>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt><\/pre>\n<\/td>\n
\n
controller_path = File<\/span>.join(directory, '<\/span>app<\/span>'<\/span><\/span>, '<\/span>controllers<\/span>'<\/span><\/span>)\r\n<\/tt>$LOAD_PATH<\/span> << controller_path\r\n<\/tt>ActiveSupport<\/span>::Dependencies<\/span>.load_paths << controller_path\r\n<\/tt>config.controller_paths << controller_path<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Ok, before we can really test this we will need to do the views, so keep going.<\/p>\n

<\/p>\n

Views<\/h2>\n

Create your view directories:<\/p>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt><\/pre>\n<\/td>\n
\n
pullmonkey$<\/span> mkdir -p app\/views\/posts\r\n<\/tt>pullmonkey$<\/span> mkdir -p app\/views\/comments<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Create your views:
\nFor this example, I will just create one, then we will test it.<\/p>\n

Views: vendor\/plugins\/simple_blog\/app\/views\/posts\/index.html.erb<\/h3>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt>7\r\n<\/tt>8\r\n<\/tt>9\r\n<\/tt>10<\/strong>\r\n<\/tt>11\r\n<\/tt><\/pre>\n<\/td>\n
\n
<h1>Posts<\/span><\/<\/span>h1>\r\n<\/tt><% @posts.each do |post| -%>\r\n<\/tt>  <h2><%= h post.subject %><<\/span>\/<\/span><\/span>h2>\r\n<\/tt>  <%= post.body %><\/span>\r\n<\/tt>  <h3<\/span>><\/span><\/span>Comments<\/span><\/<\/span>h3>\r\n<\/tt>  <% post.comments.each do |comment| -%>\r\n<\/tt>    <b>by <%= comment.username %><<\/span>\/<\/span><\/span>b><br\/>\r\n<\/tt>    <%= comment.body %><\/span><br\/<\/span>><\/span><\/span>\r\n<\/tt>    <br\/>\r\n<\/tt>  <% end<\/span> -%><\/span>\r\n<\/tt><% end -%<\/span>><\/span><\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Append your view paths:<\/h3>\n

If you don't do this next step, you will very likely see an error message like this:
\nMissing template posts\/index.erb in view path \/home\/pullmonkey\/rails_projects\/simple_blog\/app\/views:<\/p>\n

So let's add it.
\nThere are at least two ways to do this. 1) Added to your controllers individually or 2) Add to application controller globally.
\nI prefer the less obtrusive, so let's go with number 1.
\nFor this test, we will just work with the posts controller, so open it up again and add this line:<\/p>\n\n\n
\n
\r\n<\/tt><\/pre>\n<\/td>\n
\n
self<\/span>.append_view_path(File<\/span>.join(File<\/span>.dirname(__FILE__<\/span>), '<\/span>..<\/span>'<\/span><\/span>, '<\/span>views<\/span>'<\/span><\/span>))<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

So your file should look like this now:<\/p>\n\n\n
\n
1\r\n<\/tt>2\r\n<\/tt>3\r\n<\/tt>4\r\n<\/tt>5<\/strong>\r\n<\/tt>6\r\n<\/tt>7\r\n<\/tt>8\r\n<\/tt>9\r\n<\/tt>10<\/strong>\r\n<\/tt>11\r\n<\/tt>12\r\n<\/tt>13\r\n<\/tt>14\r\n<\/tt>15<\/strong>\r\n<\/tt>16\r\n<\/tt>17\r\n<\/tt>18\r\n<\/tt>19\r\n<\/tt>20<\/strong>\r\n<\/tt>21\r\n<\/tt>22\r\n<\/tt>23\r\n<\/tt>24\r\n<\/tt>25<\/strong>\r\n<\/tt><\/pre>\n<\/td>\n
\n
class<\/span> PostsController<\/span> < ApplicationController<\/span>\r\n<\/tt>  self<\/span>.append_view_path(File<\/span>.join(File<\/span>.dirname(__FILE__<\/span>), '<\/span>..<\/span>'<\/span><\/span>, '<\/span>views<\/span>'<\/span><\/span>))\r\n<\/tt>\r\n<\/tt>  def<\/span> index<\/span>\r\n<\/tt>    @posts<\/span> = Post<\/span>.all\r\n<\/tt>  end<\/span>\r\n<\/tt>\r\n<\/tt>  def<\/span> show<\/span>\r\n<\/tt>    @post<\/span> = Post<\/span>.find(params[:id<\/span>])\r\n<\/tt>  end<\/span>\r\n<\/tt>\r\n<\/tt>  def<\/span> new<\/span>\r\n<\/tt>    @post<\/span> = Post<\/span>.new\r\n<\/tt>  end<\/span>\r\n<\/tt>\r\n<\/tt>  def<\/span> create<\/span>\r\n<\/tt>    if<\/span> @post<\/span> = Post<\/span>.create(params[:post<\/span>])\r\n<\/tt>      flash[:notice<\/span>] = "<\/span>Post Created<\/span>"<\/span><\/span>\r\n<\/tt>      redirect_to :action<\/span> => '<\/span>index<\/span>'<\/span><\/span>\r\n<\/tt>    else<\/span>\r\n<\/tt>      flash[:error<\/span>] = "<\/span>Post Not Created<\/span>"<\/span><\/span>\r\n<\/tt>      render :action<\/span> => '<\/span>new<\/span>'<\/span><\/span>\r\n<\/tt>    end<\/span>\r\n<\/tt>  end<\/span>\r\n<\/tt>end<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n

Time to test<\/h3>\n

Start your web server - .\/script\/server
\nBrowse to http:\/\/localhost:3000\/posts
\nYou should see the post we created up above via Post.create(...) and its associated comment that we also created above.<\/p>\n

Note:<\/b>Feel free to overwrite any of the views. This can be done simply for the posts index view by creating the same file under RAILS_ROOT\/app\/views\/posts\/index.html.erb and doing what you'd like.<\/p>\n

<\/p>\n

That's it for part 1<\/h1>\n

Ok, so that's part 1. The goal was to keep everything external and I think we succeeded (aside from migrations).
\nNo offense to those that use engines or extract files into one's application's space, we all have our ways - the above is what I prefer.<\/p>\n

\nPart 2 will consist mainly of filling this out a bit more and further discussion on adding helpers, routes and migrations to your plugin without interfering in the application's code space.<\/p>\n

As always, have fun and good luck!<\/p>\n","protected":false},"excerpt":{"rendered":"

Update: Bloggity does not require the Engines plugin to run if you are using Rails 2.3 or above (where the Engines plugin is baked in). — Noted below by Bill. Update: Added the plugin to github – simple_blog. It is not production ready or really all that usable quite yet. Ok, so this a rant […]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[6,3,5,30],"tags":[218,210,211,43,50],"_links":{"self":[{"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/posts\/51808"}],"collection":[{"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/comments?post=51808"}],"version-history":[{"count":3,"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/posts\/51808\/revisions"}],"predecessor-version":[{"id":57337,"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/posts\/51808\/revisions\/57337"}],"wp:attachment":[{"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/media?parent=51808"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/categories?post=51808"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/pullmonkey.com\/wp-json\/wp\/v2\/tags?post=51808"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}