Archive for category Uncategorized

Working with ApplicationController in a Rails 3 Engine

UPDATE 02-13-2011: It appears that approach #2 does have a downside after all. Given my current implementation, dev will not reload the class b/c config.cache_classes is set to false. I might still try this approach using config.to_prepare.. I will update the post when I have a chance to experiment more.

Rails 3 Engines use a standard Rails app directory setup by default, so logically, you might think that you can just drop in /app/controllers/application_controller.rb, and reopen the class. This is not the case. Rails will ignore any files that have the same name as a file in the parent application. Seeing as how every Rails app has “/app/controllers/application_controller.rb”, the engine has no chance of loading this file. Poor little engine. But if your engine has a strong will… I think I can, I think I can.. then there are other ways to get your methods inside the parent app’s ApplicationController. Let’s take a look at some of the choices you have.

Option 1 – ActiveSupport.on_load

Lets start by looking at one of the most popular Rails plugins -> Devise. At the time of this writing, Devise has a helpers module that defines a class method called “define_helpers”. A mapping (user or admin) is passed to the method and several instance methods are defined using class_eval. Then these instance methods are included in the ApplicationController using the “helper_method” function. Check out how this is acheived:

ActiveSupport.on_load(:action_controller) do
  helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session"
end

on_load.. reminds me of something you would see in a javascript library. So when ActiveSupport loads the ActionController, the helper methods are inserted. You could also use a different approach within this block. Let’s say you have defined a module with submodules for ClassMethods and InstanceMethods. You would just extend/include them in the block. The most common approach for Rails 3 engines is using an initializer in the Engine class.

# You can put this in /myengine/app/models/ and it will load it automatically (or put it in your engine lib directory and require it)
module MyModule
  module ClassMethods
    def some_awesome_class_method
    end
  end
  module InstanceMethods
    def some_awesome_instance_method
    end
  end
end
#/myengine/lib/myengine/engine.rb
require "myengine"
require "rails"

module MyEngine
  class Engine < Rails::Engine
    initializer 'myengine.app_controller' do |app|
      ActiveSupport.on_load(:action_controller) do
        extend MyModule::ClassMethods
        include MyModule::InstanceMethods
      end
    end
  end
end

There are plenty of variations of the extend/include stuff that use ActiveSupport::Concern, “self.included”, “self.extended”, but they all achieve basically the same thing… adding instance and class methods.

Option 2 – Reopen the class

In the intro of this blog post, I said that Rails will not allow you to load classes from an engine with the same name as the parent app. When it comes to the ApplicationController, I am not sure if it was the intent of the Rails Core to deter you using the same name/format as the application_controller in a regular rails app… there may be use cases that I am not aware of where this is harmful or lacks functionality. It makes sense that other Engine classes with the same name/path should not be loaded since you would want the parent app to override them if it has the same controllers. This could result in clashes and unexpected consequences. But, I see the ApplicationController as a bit of a anomaly in this situation. Unless your parent app has tons of methods in the ApplicationController and the engine ApplicationController is using common method names, I don’t see this as a problem. Use fairly unique method names or prefix the method name with your plugin name if you are worried about it. There is a simple workaround to allow you to use the same format for ApplicationController that you are accustomed to seeing a standard Rails app… just prefix the file name with the plugin name for the ApplicationController. For example: /app/controllers/myplugin_application_controller.rb. Then you can add code to this file, just as I would with a Rails app ApplicationController. Check it out:

#myplugin_application_controller.rb
class ApplicationController < ActionController::Base
  before_filter :this_filter_is_the_best_thing_since_sliced_bread

  def this_filter_is_the_best_thing_since_sliced_bread
  end

  def really_cool_instance_method
  end

  def self.really_cool_class_method
  end
end

I think technically you are not reopening this class, since it gets loaded first.. so lets say we are defining the ApplicationController and the parent application is reopening the class. I did some quick tests and the Engine ApplicationController loads before the parent ApplicationController. I also wrote a spec to make sure all filters were intact using this method:

# get a list of the filter names from ApplicationController
filters = ApplicationController._process_action_callbacks.select { |c| c.kind == :before }
filter_names = filters.collect{|filter|filter.filter}
filter_names.include?(:this_filter_is_the_best_thing_since_sliced_bread).should be true #yup
filter_names.include?(:a_filter_defined_in_the_parent_app_controller).should be true #yup

Tags: , , ,

Making the case for Rails 3 Engines

Engines have been around for a while now in some for or another, but with the release of Rails 3, they became an integral part of the framework, and IMO they make it easy for any developer to create a plugin. Rails 3.1 will make Engines even better thanks to the SOC work done by Piotr Sarnacki, but I will be focusing on what is available in Rails 3.0.3 in this post.

Engine? Say what??

In case you are not familiar with Rails 3 Engines, in a nutshell… they are sub-applications that are packaged as gems and can run inside a standard Rails application. They give you most of the functionality of a standard rails app, including the controllers, views, helpers, configuration, etc… Engines lay the groundwork of having “mountable” apps in Rails.

So, why should I care?

I think this is useful on 2 fronts. The first being fully functional sub-applications such as a blogging engine. You could drop the engine into your Gemfile and you would immediately have the functionality of a full-featured blog that is running in the same process as your parent app. The second use is of more interest to me, although I have seen little discussion about it. I guess you could call it building blocks. These engines would be smaller than something like a blog. For example, lets say you want to add comments to your application. Right now I think most people would probably look at something like this: https://github.com/jackdempsey/acts_as_commentable. Pretty cool. It gives you a migration, a model and the polymorphic association needed to make a model “commentable”. But you are left with implementing the views & controller yourself. Although it is not terribly difficult to implement this, it still takes some time to do it. Let’s look at how an Engine could improve this plugin. You could basically do everything with 4 lines of code and a few commands.

#Gemfile
gem 'comment_engine'

# command shell - add the migration and run it
rails g comment_engine
rake db:migrate

#model
class Article < ActiveRecord::Base
is_commentable
end

#view
<%=comment_form(@article) %>
<%=comment_list(@article) %>

So you add the engine to your Gemfile, you make your model commentable and you use 2 helpers in your view. This will give you a fully functional comment form in your view and list of comments associated with that model. So how does the Engine make this so easy? You can use controllers, routes, partials, and helpers. So the plugin would include the following:

1. comment.rb – your comment model
2. generator – migration template for Comment
3. Commentable module – AR::Base will extend this module. Uses polymorphic associations to allow models to be “commentable”
4. Helper module – included in the parent app’s application_helper. This provides some shortcuts like comment_form and comment_list. Basically these methods take the model and generate a form or list based on that commentable model.
5. comments_controller.rb – has a create method that creates the comment and redirects to :back.
6. routes.rb – adds resource routes for comments.

While these are the necessities, there are plenty of other things that you could add to an engine like this, for example: attaching the authenticated user to the comment.

This makes development a breeze, as long as you have good defaults in the Engine. One of the main things that “building block” engine authors should focus on is the view portion of this. This is a fairly new concept when it comes to Rails plugins and I have not seen it implemented in many plugins. The plugin needs to be easy to style or give the developer the choice to completely override the view with their own. I guess it is also important to allow the parent app developer to override or add functionality to the controllers and models. The tricky part about that is re-opening the classes. Rails blocks the engine classes from loading if they are the same file name/path as something in the parent app. This is a concept that I am still exploring. Ideally, you would want to allow the developer to drop in a class with the same path that would reopen the class from the engine. Although this could be dangerous if the app developer is not aware of the class in the Engine, IMO it would be very useful if you use it wisely.

How I have been using Engines

I started working with Engines using the Rails 3 betas, and I am still working on figuring out the best practices. Although I am still experimenting quite a bit, Engines have become a major part of my workflow. IMO, the Engine plugin is the most important addition to Rail 3, since they make your code extremely modular and can increase your productivity by quite alot. I am really looking forward to seeing what kind of “building blocks” are created using this plugin architecture. Here is what I have focused on so far for my own environment:

1. authentication_engine – basic and simple authentication that includes signup, login and roles.  Views and controllers included.
2. social_engine - includes comments, ratings, reviews, votes, reputation, and helpers for things like facebook like and tweetmeme. Most if this is impelemented in the same manner as I described for the comments engine at the beginning of this post
3. ui_engine – includes good defaults for the base layout, a configuration for the layout, css, javascript, and plenty of partials that you can override in the parent app. Based on HTML5 boilerplate. My intention with this engine is to get rid of all the BS work you have to do for your front end. I know layout and view stuff differs alot per application, but I find myself doing alot of the same things for each app when it comes to UI.

I am working on extracting alot of the code into an open source plugin for #2 and #3. I should have the social_engine on github in the next few weeks. The UI engine definitely needs alot of work, in order to be useful to developers other than myself.

Conclusion

I love Rails and Rails 3 is leaps and bounds above the previous versions in terms of modularity and extensibility. I like the fact that it has a solid base architecture that plugins can sit on top of. Although there are plenty of productivity gains by using Rails alone, I think the plugins that sit on top of Rails give you the greatest productivity gains. I am looking forward to seeing the Engine ecosystem that is sure to develop in the next few years.   I think it will remove many of the mundane development tasks that developers have to worry about currently, allowing us to focus more on stitching together the building blocks that we need for our applications to function… not on the details of creating these building blocks.

Thoughts?  Leave me a comment

Tags: ,

Developing is_able or acts_as plugins for Rails 3 – Part 1

Note: This is an introduction explaining the concept of “acts_as”. This will not go into detail about creating the plugin.. only the basic description of the functionality of the plugin. Part 2 will go into detail about creating the structure outside of  this and making it a real plugin.


You have seen them everywhere in the Rails world. Acts as this, Acts as that, Is able…. Most of these plugins have the same goal: Allow any ActiveRecord subclass to “have many” of another specific AR subclass. For example, acts_as_taggable_on allows a post, article, product, or any other AR model to have many tags. Hence the name “taggable”. These plugins take care of the associations for you, by adding only one extra database table to your schema. You don’t have to alter the “able” model’s table structure to make it work. “Able” plugins do this by using polymorphism. It is actually quite simple to create something that is “able” using Rails 3. In this tutorial, I will create the code directly in the Rails app, instead of using a gem (so as the introductory note states… this is not a real plugin yet). Check it out:

Requirement:

Create a plugin that allows any ActiveRecord model to have many reviews.  Reviews will have a rating, a text review, pros, cons, and a user ID

Implementation:

1. Create the review Model

Easy enough to create using Rails generators:

rails g model review rating:integer review_text:text pros:string cons:string user_id:integer reviewable_type

2. Define the polymorphic associations in the model and migration

You will need to add this line to your migration in order to generate the 2 extra columns for polymorphism (reviewable_type,reviewable_id)

t.references :reviewable, :polymorphic => true

This will spit out our migration and create the Review model.

Next we will add the polymorphic association to the Review class that was just generated:

class Review < ActiveRecord::Base
   belongs_to :reviewable, :polymorphic=>true
end

Basically, this tells Rails that you want to the Review to belong to “reviewable” and “reviewable” can be any other type of model.  Behind the scenes, Rails just looks at the “reviews” table for “reviewable” using the “reviewable_type” and “reviewable_id”.  This may be a little confusing if you are not familiar with polymorphic associations in Rails.  Lets take a look at how the records actually show up in the table and it may make a little more sense:

id | reviewable_type  | reviewable_id | review_text |
1  | "Product" | 99 | "my review of product #99" |
2  | "Article" | 25 | "my review of article #25" |

As you can see, each row represents a single review, but each review belongs to a different model instance. Review #1 belongs to Product #99, and review #2 belongs to Article #25. By creating the 2 “reviewable” columns, you are able to associate a review with more than one model class.

3. Run the migration

rake db:migrate

4. Create a module that ActiveRecord::Base will extend

This allows you to keep things DRY and simple in each model that is “reviewable” (has_many :reviews). You can drop this into your /app/models directory.

module Reviewable
  def is_reviewable
    has_many :reviews, :as=>:reviewable, :dependent=>:destroy
    include InstanceMethods
  end
  module InstanceMethods
    def reviewable?
      true
    end
  end
end
ActiveRecord::Base.extend Reviewable

First, lets look at the last line in the code above. When this Ruby file is evaluated it will make ActiveRecord::Base extend Reviewable. Basically when you extend a module, the class methods are added to the class that is extending the module. So ActiveRecord::Base now has a class method named “is_reviewable”. Since all your models extend ActiveRecord::Base, they will also respond to this class method.

Next take a look inside the class method. The “is_reviewable” method calls the “has_many” class method and also adds an instance method to the ActiveRecord::Base subclass instance. Lets take a look at a real example that would use the “is_reviewable” class method.

class Product < ActiveRecord::Base
   is_reviewable
end

This used to look like some kind of magic to me when I was a Rails novice. Its just a nice DSL, but behind the scenes this line is calling a class method. Since this line is not in a “def”, the class method will be executed immediately when the class is loaded by Rails. in other words… self.is_reviewable. The class is loaded, the method is executed and has_many (also a class method) is executed and the methods defined in the InstanceMethods module are included in the Product class.

5. Try it out

For simplicity I will not include the tests here, but please note that it is important to create tests using Rspec (or whatever framework you prefer) for all of this code.  These console lines could easily be translated into a test spec.

Lets see this in action in the Rails console:

#check to see if the class method is there for AR Base
ActiveRecord::Base.methods.include?(:is_reviewable) => true

#check to see if class method is there for Product (has to be b/c it subclasses AR Base)
Product.methods.include?(:is_reviewable)
=> true

#check to see if the instance method is there
Product.instance_methods.include?(:reviewable?)
=> true
product = Product.new
=> #

product.reviewable?
=> true

product.reviews
=> [] #nothing here yet.. we havent created any

product.reviews.create(review_text: "test")
=>  #this results in error.. you can create a review until the product has been saved

product.save
product.reviews.create(review_text: "test")
=> #<Review id: 1, reviewable_type: "Product", reviewable_id: 101 ....>

product.reviews.size
=> 1

Conclusion

It looks a bit complicated and magical when you first encounter these plugins, but in reality its as simple as adding a class method to AR. Please read this blog by Yehuda Katz which shows how some people make the extends/includes thing alot more complicated than it should be. I was using the “overkill” way before I read his post. It totally makes sense and removes some of the confusion you may have when looking at the source of some of the “able” plugins.

Tags: , , , ,

Reloading Rails 3 Engine initializers in development

I am creating a Rails 3 Engine and I added a few initializers to the engine class. 2 of them include modules in the main app’s classes at runtime. One includes some methods in the application_helper.rb and the other adds class methods to controllers using class_eval. It works fine in production mode because config.cache_classes=true. But in development, all the application classes are reloaded on every request, since development defaults to cache_classes=false. This was bugging me for a bit as I tried to find a clean way to reload the initializers on each request. After trying a few different things I came across a better solution. Remove the code from the initializer block and do this instead:

    config.to_prepare do
      ActionView::Base.send(:include, MyEngineHelper)
      MyEngineControllerStuff.add_class_methods
    end

The config.to_prepare block is run once in production and on every request in development mode. So this only pertains to code that reopens your app’s classes. If you are doing something like including a module in ActiveRecord, you can still use an initializer b/c it will not reload the ActiveRecord class.

Password protect your entire site with Nginx

I am releasing a new web app in the next few weeks, but I want to go ahead and put it online to get feedback from beta testers. I do not want the public to see the site yet, so I need to password protect it. The quickest way to do this IMO is using basic http authentication. This gives you the generic authentication popup in your browser when you access the site. Its very easy to change the Nginx config and enable basic authorization. Open up your Nginx config in an editor.. in my case I use:

cowboycoded$  vi /usr/local/nginx/conf/nginx.conf
server {
    auth_basic            "Restricted";
    auth_basic_user_file  /usr/local/nginx/conf/htpasswd;
}

The code above will restrict all traffic to your server. But, if you just need to protect one directory, you can put this in the “location” block

server {
  #server stuff here
  location /
    auth_basic            "Restricted";
    auth_basic_user_file  /usr/local/nginx/conf/htpasswd;
    # other location stuff here
  }
}

Add the 2 auth_basic lines shown above and save your file. Then you will need to create the htpasswd file manually so you can give your users access. If you have apache installed (why would you if u are using nginx??), then you can use the htpasswd shell command. Since I don’t have apache installed, I just create the password using irb. do this:

cowboycoded$  irb
cowboycoded$  irb(main):001:0> “mypassword”.crypt(“salt”)
cowboycoded$  => “sayVb7E97UXnw”

Now create the htpasswd file in /usr/local/nginx/conf/

cowboycoded$  vi /usr/local/nginx/conf/htpasswd

Add the line for your username and encrypted password from irb and save the file.

username:sayVb7E97UXnw

Now you need to restart nginx for the changes to work:

cowboycoded$  sudo killall -9 nginx;sudo /usr/local/nginx/sbin/nginx

Access your website and it should prompt you for a password now.

UPDATE – For those of you using Ruby on Rails, you may want to check out my plugin called lock. It does basically the same thing, except inside your Rails app.

Quickie: Transferring files server to server using scp

Do you use FTP to transfer files?  Not me.. at least not in a long time.  There is an easier way that requires less setup on the server, less open connections and better security.  I am talking about “scp”, of course.  Instead of installing and running an FTP daemon, you can use your ssh daemon to accept the connections and transfer the files.  Since I set up SSH for terminal sessions on all my servers, I figured I may as well use the port for file transfer as well.  I transfer files using 2 methods that interact with SSH.

1.  Filezilla

I am sure you have probably heard of this one.  Filezilla allows you to transfer files over SFTP (SSH FTP).  I have my connections saved, so in just a few clicks with the Filezilla GUI, I can transfer a file from a remote server to my local box.  Note that scp is faster than SFTP, so when I am transferring a large file, I use scp instead.

2. scp command line

If I am transferring from remote server to remote server (or large files remote to local) I use scp.  The commands are simple.

scp command example for transferring a file from some other server to the server you are logged into (INBOUND):

scp username@some-other-server.com:/path/to/remote/file.txt /path/to/put/file/on/local

scp command example for transferring a file from the server you are logged into over to some other server (OUTBOUND):

scp /path/to/local/file.txt username@some-other-server.com:/path/to/output/remote/file

Tags: ,

Better web steps for Cucumber with Capybara

I just finished reading You’re Cuking It Wrong by Jonas Nicklas (the Capybara guy). This blog post makes total sense, and led me to write my own steps for Cucumber which are more readable for the non-technical. I have been using CSS and XPath selectors in some of my steps and I have noticed the ugliness along the way. I still think its useful to include things related to CSS in cuke scenarios, though. For example, you may want to describe what is shown on the page and break it up into sections. Let say you have a client that wants some text that says “If you need help, then RTFM” in the help section of the home page . I would write something like this before:

  Given I am on the home page
  Then I should see "If you need help, then RTFM" within "#help"

This could be converted to:

  Given I am on the home page
  Then I should see "If you need help, then RTFM" in the "Help" section

This gets rid of the ugly css stuff and makes it actually read like an english sentence. This also fits nicely with the new section tag in HTML5. This sentence makes sense to me and the people that I work with, but maybe not so much to you and your stakeholders. If you think a different sentence would be easier to read, then by all means write it that way. The whole point of this is to make the scenarios easy to read for the business owners as well as the developer, and with the flexibility provided by cucumber, you can make it read the way you want it to. The accompanying web steps for my sentence would look like this:

Then /^I should see "([^"]*)"(?: in the "([^"]*)" section)?$/ do |text,section|
  with_scope(section,:css_id) do
    page.should have_content(text)
  end
end

In order to make the sentence more readable, I made the section name accept capitalized words with spaces. This will not match the CSS IDs or classes, so I had to convert the words prior to checking with_scope. Since I will be using this on more than one step definition, I figured I might as well monkey patch the with_scope method to accept my format. That way, I can just pass the css selector type I am looking for (class or ID) and it will convert the capitalized/spaced words into a css class. I also monkey patched String and added a ccserize method which converts “My Section” into “my-section”. I prefer to use dashes to separate words when writing CSS classes or IDs. I also like this approach, because it forces you to make your css IDs descriptive based on what the customer wants.

class String
  def csserize
    self.downcase.gsub(" ","-")
  end
end

module WithinHelpers
  def with_scope(locator,css_type=nil)
    locator = convert_locator_to_css(locator,css_type) if locator and css_type
    locator ? within(locator) { yield } : yield
  end

  def convert_locator_to_css(locator,css_type)
    locator = locator.csserize
    return locator if locator =~ /^[.#]/
    css_type==:css_class ? ".#{locator}" : "##{locator}"
  end
end

The code above patches the with_scope method, so that it can convert to my css class format if the “css_type” parameter is present. Basically this just converts to lowercase, replaces spaces with dashes and appends a hash mark or a period depending on if it is a class or ID selector. Now that I am looking at it closer, I should probably change it so that it converts and searches for ID and class without me even specifying… so if it does not find anything initially, it converts with csserize, then looks for a class, then looks for and ID if it does not find a class.

There are countless possibilities when writing your own web step DSL. I think it is important to take some time to sit down and figure out the language that is most appropriate for you and the your customers, before you write any more scenarios. Take a look at what you have written in the past and contemplate whether you can write it in a simpler, easier to understand format. If you think anyone in your business (tech or non-tech) would not understand a particular sentence, then it needs to be changed. The beauty of Cucumber is allowing anyone to write requirements using a language that all stakeholders can understand.

Here are a few more custom web steps I wrote, so you can see more examples:

# Then I should see a page heading named "Widgets" in the "Main" section
Then /^I should see a page heading named "([^"]*)"(?: in the "([^"]*)" section)?$/ do |text, section|
  with_scope(section,:css_id) do
    page.should have_selector("h1",:text=>text)
  end
end

# Then I should see a link named "Buy this widget" in the "Product Details" section
Then /^I should see a link named "([^"]*)"(?: in the "([^"]*)" section)?$/ do |text, selector|
  with_scope(selector,:css_id) do
    page.should have_link(text)
  end
end

I would love to see more examples on the internet for custom web steps (especially using Capybara). I had a hard time finding anything when Googling for some of this stuff. I am planning on building a web app some time in the future where people can share their web steps. I think it would be very useful to see what others are doing, so you don’t have to reinvent the wheel. If you have any custom steps that you would like to share, please comment with a link!

Tags: , ,

Gem dev tutorial: Adding Rails 3 Engines to Jeweler

If you are a Ruby or Rails developer, chances are you will run into a situation where you want to modify a gem that is on github.  In this tutorial I will show you a real-world example of how I do this, using Jeweler as an example.

I like Jeweler.. I like it alot.. but I always end up creating a gem with it and then tweaking a bunch of files to turn it into a Rails 3 Engine. So I am attempting to integrate Rails 3 engines into Jeweler by adding a command line argument that will tell jeweler to create the engine directories and add the engine file templates.

Fork The Repo

First, I need to fork the repo so I can add my changes. I just login to my github account and go to the jeweler page and click the fork button. Now I have a repo under my account. Then I clone the repo on my dev box. In order to pull changes from the original repo when anything changes, I will need to add a remote upstream:

#clone my forked repo
git clone git@github.com:johnmcaliley/jeweler.git
#add upstream that points to original repo
git remote add upstream git://github.com/technicalpickles/jeweler.git

Test Driven Development

I see that this project uses Cucumber for many of its tests. This time I decide to be a good boy and do some TDD from the get-go. The first thing I want to do is create a cuc feature and write 2 scenarios. The first is a scenario without the –rails3_engine argument. The second is with the argument. I used some of the steps from the cucumber.feature in order to get up and running.

Feature: generating rails3 engine directories and files
In order to use rails 3 engines with jeweler generators
A user should be able to
generate a project setup and specify the rails3_engine option

Scenario: sans rails3 engine setup
Given a working directory
And I have configured git sanely
And I do not want to create a rails 3 engine
When I generate a project named ‘the-perfect-gem’ that is ‘zomg, so good’
Then a file named ‘the-perfect-gem/app’ is not created
And a file named ‘the-perfect-gem/app/controllers’ is not created
And a file named ‘the-perfect-gem/app/helpers’ is not created
And a file named ‘the-perfect-gem/app/models’ is not created
And a file named ‘the-perfect-gem/app/views’ is not created
And a file named ‘the-perfect-gem/lib/the-perfect-gem’ is not created
And a file named ‘the-perfect-gem/lib/the-perfect-gem/engine.rb’ is not created
And a file named ‘the-perfect-gem/lib/generators’ is not created
And a file named ‘the-perfect-gem/lib/the-perfect-gem/railties’ is not created
And a file named ‘the-perfect-gem/lib/the-perfect-gem/railties/tasks.rake’ is not created

Scenario: Rails 3 engine setup
Given a working directory
And I have configured git sanely
And I want to create a rails 3 engine
When I generate a project named ‘the-perfect-gem’ that is ‘zomg, so good’
Then a file named ‘the-perfect-gem/app’ is created
And a file named ‘the-perfect-gem/app/controllers’ is created
And a file named ‘the-perfect-gem/app/helpers’ is created
And a file named ‘the-perfect-gem/app/models’ is created
And a file named ‘the-perfect-gem/app/views’ is created
And a file named ‘the-perfect-gem/lib/the-perfect-gem’ is created

And a file named ‘the-perfect-gem/lib/generators’ is not created
And a file named ‘the-perfect-gem/lib/the-perfect-gem/railties’ is created
And a file named ‘the-perfect-gem/lib/the-perfect-gem/railties/tasks.rake’ is created
And ‘the-perfect-gem/lib/the-perfect-gem/railties/tasks.rake’ is blank

And a file named ‘the-perfect-gem/lib/the-perfect-gem/engine.rb’ is created
And ‘the-perfect-gem/lib/the-perfect-gem/engine.rb’ requires ‘the-perfect-gem’
And ‘the-perfect-gem/lib/the-perfect-gem/engine.rb’ requires ‘rails’
And ‘the-perfect-gem/lib/the-perfect-gem/engine.rb’ has a module based on the class name
And ‘the-perfect-gem/lib/the-perfect-gem/engine.rb’ subclasses rails engine
And ‘the-perfect-gem/lib/the-perfect-gem/engine.rb’ has placeholders for initializers and rake task inclusion

These scenarios have some steps that are not defined, so obviously they will fail. I need to add the missing step definitions.

##features/step_definitions/generator_steps.rb

Given /^I do not want to create a rails3 engine$/ do
  @rails3_engine = false
end

Given /^I want to create a rails3 engine$/ do
  @rails3_engine = true
end

# one line added here also:
When /^I generate a (.*)project named '((?:\w|-|_)+)' that is '([^']*)' and described as '([^']*)'$
#....
  @use_cucumber ? '--cucumber' : nil,
  @rails3_engine ? '--rails3_engine' : nil, # I added this
#....
end

Then /^'(.*)' has a module based on the class name$/ do |file|
  content = File.read(File.join(@working_dir, @name, file))

  assert_match %Q{module ThePerfectGem}, content
end

Then /^'(.*)' is blank$/ do |file|
  content = File.read(File.join(@working_dir, @name, file))

  assert_match "", content
end

Then /^'(.*)' subclasses rails engine$/ do |file|
  content = File.read(File.join(@working_dir, @name, file))

  assert_match "class Engine < Rails::Engine", content
end

Then /^'(.*)' has placeholders for initializers and rake task inclusion$/ do |file|
  content = File.read(File.join(@working_dir, @name, file))

  assert_match "#rake_tasks do", content
  assert_match '#load "the-perfect-gem/railties/tasks.rake"', content
  assert_match "#initializer 'the-perfect-gem.helper' do |app|", content
  assert_match "#ActionView::Base.send :include, ThePerfectGemHelper", content
end

Then /^'(.*)' requires the engine$/ do |file|
  content = File.read(File.join(@working_dir, @name, file))

  assert_match 'PATH = File.dirname(__FILE__) + "/the-perfect-gem"', content
  assert_match 'require "#{PATH}/engine.rb"', content
end

Dig Into The Existing Code

Next I need to figure out how this thing works and add my code.

The gem contains a binary file under /bin that includes the jeweler libraries and then fires off a generator that accepts arguments

require 'jeweler/generator'
exit Jeweler::Generator::Application.run!(*ARGV)

The run class method is in lib/generator/application.rb. It does some checks on the options and then creates an instance of Jeweler::Generator and calls its run method

generator = Jeweler::Generator.new(options)
generator.run

Make changes to generator.rb

Taking a closer look at the initialize method, I see that I will need to add something for the “rails3_engine” argument that I pass to the jeweler binary. I will add something similar to the cucumber option

self.should_use_cucumber    = options[:use_cucumber]
self.should_create_rails3_engine = options[:rails3_engine] # added this code

I also need to add an attribute accessor so the object can set this instance variable:

attr_accessor   # a bunch of existing attr_accessors listed here.. append mine to end of list
,:should_create_rails3_engine

I think that will do for the initialize stuff. Next I look at the run instance method. It has a method called create_files. I will need to add a condition to this method so Jeweler can check for my rails3_engine option and create the appropriate files. Again I look at the cucumber option for inspiration, since it creates directories in the gem and adds files.  Similar to the cucumber condition, the “rails3_engine” option will create some directories and output my engine template files into these directories.

if should_use_cucumber
  mkdir_in_target           features_dir
  output_template_in_target File.join(%w(features default.feature)), File.join('features', feature_filename)

  mkdir_in_target           features_support_dir
  output_template_in_target File.join(features_support_dir, 'env.rb')

  mkdir_in_target           features_steps_dir
  touch_in_target           File.join(features_steps_dir, steps_filename)
end

# here is what I added
if should_create_rails3_engine
  mkdir_in_target           app_dir
  mkdir_in_target           controllers_dir
  mkdir_in_target           models_dir
  mkdir_in_target           helpers_dir
  mkdir_in_target           views_dir
  mkdir_in_target           main_dir
  output_template_in_target File.join('rails3_engine','engine_template.erb'), File.join(main_dir,'engine.rb')
  mkdir_in_target           generators_dir
  mkdir_in_target           railties_dir
  touch_in_target           File.join(railties_dir,'tasks.rake')
  output_template_in_target File.join('rails3_engine','lib_engine_template.erb'), File.join(lib_dir,lib_filename)
end

I also need to add instance variables for the directories that are used in the rails3_engine option condition. Again, I look at what was coded for cucumber:

#check for a dash in the project name and convert to underscore so classify understands it
def project_class
  self.project_name.gsub("-","_").classify
end

def app_dir
  'app'
end

def controllers_dir
  "#{app_dir}/controllers"
end

def models_dir
  "#{app_dir}/models"
end

def views_dir
  "#{app_dir}/views"
end

def helpers_dir
  "#{app_dir}/helpers"
end

def main_dir
  "#{lib_dir}/#{self.project_name}"
end

def generators_dir
  "#{lib_dir}/generators"
end

def railties_dir
  "#{main_dir}/railties"
end

Since I use the pluralize method in “project_class” I need to include active_support inflectors in the Jeweler class

require 'git'
require 'erb'
require 'active_support/inflector' # I added this one
require 'net/http'
require 'uri'

Add code to options.rb

One part that I notice is missing while looking at how cucumber is set up is the code in lib/jeweler/generator/options.rb.

o.on('--cucumber', 'generate cucumber stories in addition to the other tests') do
  self[:use_cucumber] = true
end

# I added this
o.on('--rails3_engine', 'generate rails3 engine directories and files') do
  self[:rails3_engine] = true
end

Add the file templates

generator.rb makes a few calls with methods like this:

output_template_in_target File.join('rails3_engine','engine_template.erb'), File.join(main_dir,'engine.rb')

I created a directory called “lib/jeweler/templates/rails3_engine” that will house my template files. Then I add 2 erb templates that will generate the source code files dynamically in the gem.
Here are the files:

##engine_template.erb
require "<%=require_name%>"
require "rails"

module <%=project_class%>
  class Engine < Rails::Engine
      #rake_tasks do
        #load "<%=require_name%>/railties/tasks.rake"
      #end

      #initializer '<%=require_name%>.helper' do |app|
        #ActionView::Base.send :include, <%=project_class%>Helper
      #end
  end
end
##lib_engine_template.erb
PATH = File.dirname(__FILE__) + "/<%=require_name%>"
require "#{PATH}/engine.rb"

The first file creates the engine.rb which is necessary to make our gem behave as a Rails 3 engine plugin. Using erb allows me to insert text dynamically based on the project name and the require directory which were set in generator.rb instance methods. The second file is just a simple template that requires engine.rb in the project.

Fire off them tests man!

This tutorial does not reflect what I actually did in development.  I run my tests first, look at the failures, write code, refactor, then repeat until everything is green as a cuc.  But to simplify, I am just showing that you need to run tests after you write your code.  Jeweler uses a rake task to execute all the cuc scenarios, so I run this command:

rake features
103 scenarios (103 passed)
652 steps (652 passed)

Now I can see all of my scenarios as well as existing scenarios are all passing. Good to go!

I also updated the unit test, test_options.rb.  But I am getting some errors relating to ‘rr’ -> “NotImplementedError: super from singleton method that is defined to multiple classes is not supported; this will be fixed in 1.9.3 or later”.  I don’t think I will be able to run these tests until I get this resolved.  Looks like it is an issue with ‘rr’ and ruby 1.9.2.  I might try downgrading ruby using RVM and running from there.

Test with a live app

After the cucumber tests are passing, I want to look at this in a real Rails 3 app.  So I create a new gem using my jeweler fork. I just execute the jeweler bin from my fork:

>cd jeweler
>bin/jeweler myengine --rails3_engine
create  .gitignore
create  Rakefile
create  Gemfile
create  LICENSE.txt
create  README.rdoc
create  .document
create  lib
create  lib/myengine.rb
create  test
create  test/helper.rb
create  test/test_myengine.rb
create  app
create  app/controllers
create  app/models
create  app/helpers
create  app/views
create  lib/myengine
create  lib/myengine/engine.rb
create  lib/generators
create  lib/myengine/railties
create  lib/myengine/railties/tasks.rake
create  lib/myengine.rb
Jeweler has prepared your gem in myengine

I add a controller and a view to the gem, create a gemspec and install my gem. Then I add the gem to a rails 3 app Gemfile (using :path=>/path/to/my/gem), bundle install, fire up the app server and take a look at the view that I added.

It appears, so I know that the Engine was initialized in the app. Good to go!

Here is the fork if you want to look at the code:
https://github.com/johnmcaliley/jeweler

Tags: , , , , , ,

Setting up Rails 3 on Mac OSX Snow Leopard 10.6.4

I finally made the complete switch to Mac this weekend.  I have been using my iMac at work for about a year and I love it, but I have been holding on to my Dell laptop and more and more every day I feel like throwing it through a window, so I decided to bite the bullet and buy a Macbook Pro so I could be more productive at home.  Here is a step by step guide of how I set it up to work with Rails 3.

1. Install git and RVM

RVM is a great way to manage multiple ruby versions on your Mac, and it also makes installing any version dead simple.  You will need to install “git” before you can install RVM.  I downloaded the git DMG from here:

http://git-osx-installer.googlecode.com/files/git-1.7.3.2-intel-leopard.dmg

Install git from the DMG and then you can install RVM afterwards.  Note that you will have to restart your terminal session in order to use the git command.

Install RVM by issuing the following commands in your shell:

Now you should be good to go with RVM. Here is the install guide if you run into any problems: http://rvm.beginrescueend.com/rvm/install/

Install a C Compiler (by installing XCode)

You will need a c compiler to install ruby using RVM.  You can download XCode, which has a c compiler, from the Apple website.  I downloaded the iOs/XCode package since i will probably be developing iPhone apps as well.  This is a mamoth download (3+ GB), so be prepared to wait a while.

If you dont feel like waiting that long for the download, pop in the OSX DVD that came with your Mac and when the startup screen appears, choose “Optional Installs”, and you can install XCode from there (without iOS stuff).

Install Ruby 1.9.2

cowboycoded$  rvm install 1.9.2

Simple as that!  This may take a few minutes to compile and install.  RVM will also install RubyGems, so its not necessary to do that manually.  Snow Leopard ships with Ruby 1.8.7, so you will need to switch to version 1.9.2 after you install it with RVM.  Use RVM to switch versions.

cowboycoded$  rvm 1.9.2

Verify that you are using 1.9.2

cowboycoded$  ruby -v

Set 1.9.2 as the default Ruby in RVM, so you don’t have to switch every time you open a new shell

cowboycoded$  rvm --default use 1.9.2

Install Ruby on Rails 3

cowboycoded$  gem install rails

This will install Rails 3 and all of its dependencies.  At the time of this writing the current version was 3.0.3.  I use MySQL for all of my apps, so I need to install that also.

Download and install MySQL server

http://dev.mysql.com/downloads/mysql/

Its probably easiest to download the DMG and install it that way.  Get the 64 bit DMG if you are using Snow Leopard.  Probably a good idea to install the MySQL Startup Item that is in the DMG as well.  This will start MySQL when your Mac boots.

After you install you can use the Startup Item to start MySQL manually:

cowboycoded$  sudo /Library/StartupItems/MySQLCOM/MySQLCOM start

If you are using the mysql gem (v2.8.1), then you will likely run into a problem when you bundle install. Install the gem manually using this command instead:

cowboycoded$  sudo env ARCHFLAGS="-arch x86_64" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config

Test it out

You should have everything you need at this point.  Fire up a new rails app and make sure everything worked:

cowboycoded$  rails new test_app
cowboycoded$  cd test_app
cowboycoded$  bundle install
cowboycoded$  rails s

Tags: , , , , ,

Quickie: Setting AUTO_INCREMENT for a MySQL table

Not exactly a thrilling blog post, but I always forget the exact syntax for this for some reason, so I am putting it in my blog so I can easily find it.  Sometimes I find myself wanting to set the AUTO_INCREMENT start number back to one.  This is usually when I populate a new table, and end up deleting all the data in the table and then decide to repopulate it.  For example if I inserted 4000 records in a table and then deleted them, AUTO_INCREMENT would be set to 4001.  When I re-insert these 4000 records I would prefer it to start at id=1 instead of id=4001 to keep things clean.  Its as easy as running a simple ALTER statement:

#both of these will start you at id=1 when you insert your next record
ALTER TABLE my_table AUTO_INCREMENT=0
ALTER TABLE my_table AUTO_INCREMENT=1

Just to see what happened, I inserted a few test records into the database and then set the AUTO_INCREMENT back to “1″. I was expecting an error when I inserted the next record since the id=1 already existed and AUTO_INCRMENT id field has to be unique. But MYSQL can detect this and it automatically auto increments to the next available id. So if I have 3 records with ids= [1,2,3] then I set AUTO_INCREMENT to “1″, the next record I insert will be ID=4. Same thing if you have ids = [2,3,4]. MySQL skips “1″ and the next record id will be “5″. According to some of the comments in the MySQL documentation, it uses the following formula when setting the ID to “0″ or “1″:

1 + max(AUTO_INCREMENT)

Tags: , ,