Skip to main content

Mobomo webinars-now on demand! | learn more.

Intridea is excited to participate in the AWS Start-Up Challenge.

We've entered three of our applications:

Scalr is a self-curing and auto-scaling environment built on EC2 and S3. Scalr makes it dead simple to create, configure, and maintain a custom server farm for your application that's fully redundant, self-curing and scales automatically based on load averages.

MediaPlug allows site operators, developers, and entrepreneurs to add images, audio and video to their websites at a fraction of the cost. It's a white-label plug-and-play solution that provides image, audio and video transcoding to dozens of popular formats.

SocNet is an extensible and fully customizable full-featured white-label social networking platform.

All three products will officially be beta launched November 5.

Categories
Author

First the database migration used in all examples (using Rails 2.0 sexy migrations):

class CreateClassifications < ActiveRecord::Migration    def self.up      create_table :classifications do |t|        t.integer :parent_id        t.integer :lft        t.integer :rgt        t.string  :name        t.text    :description        t.timestamps      end    end      def self.down      drop_table :classifications    end  end

Please note that the left and right columns are named in such a way that they will not conflict with database reserved words commonly used in join statements.

Then the code:

class NestedSet < ActiveRecord::Base    acts_as_nested_set      def self.all_parents      self.roots.map do |root|         (root.full_set.collect {|child| child if child.children.size > 0}).compact.flatten      end    end      def self.all_leaves      self.roots.map do |root|         (root.full_set.collect {|child| child if child.children.size == 0}).compact.flatten      end    end    end

This code works - but works slowly and yields horrific SQL. The reason it's slow and horrific is because you need to hit each node in the tree to test for it's number of children. This is less than ideal especially if you need to do this regularly (or on a tree with hundreds of nodes) - which leads us to the next iteration:

class NestedSet < ActiveRecord::Base    acts_as_nested_set      def self.all_parents      self.find(:all, :conditions => "rgt <> lft + 1")    end      def self.all_leaves      self.find(:all, :conditions => "rgt = lft + 1")    end    end

This works much better and is far more efficient. Each call to the class method makes a single query to the database. The reason the we can do this is because of the way nested sets work. A good explaination of this can be found in the BetterNestedSet README:

An easy way to visualize how a nested set works is to think of a parent entity surrounding all  of its children, and its parent surrounding it, etc. So this tree:      root      |_ Child 1        |_ Child 1.1        |_ Child 1.2      |_ Child 2        |_ Child 2.1        |_ Child 2.2    Could be visualized like this:      ___________________________________________________________________     |  Root                                                             |     |    ____________________________    ____________________________   |     |   |  Child 1                  |   |  Child 2                  |   |     |   |   __________   _________  |   |   __________   _________  |   |     |   |  |  C 1.1  |  |  C 1.2 |  |   |  |  C 2.1  |  |  C 2.2 |  |   |     1   2  3_________4  5________6  7   8  9_________10 11_______12 13  14     |   |___________________________|   |___________________________|   |     |___________________________________________________________________|     The numbers represent the left and right boundaries.  The table then might  look like this:       id | parent_id | lft  | rgt  | data      1 |           |    1 |   14 | root      2 |         1 |    2 |    7 | Child 1      3 |         2 |    3 |    4 | Child 1.1      4 |         2 |    5 |    6 | Child 1.2      5 |         1 |    8 |   13 | Child 2      6 |         5 |    9 |   10 | Child 2.1      7 |         5 |   11 |   12 | Child 2.2

You can also check out additional nested set explanation in an article titled "A Nested Set Implementation..." (paying special attention to the illustrations in section #3).

Going back to our example, there's one more thing we can to do make this one step better - move our methods into the plugin implementation. This makes sense as our class methods are not directly related to our application logic and pertain mainly to nested set behavior.

You can add a version of our methods to the nested set plugin by adding to the ClassMethods module in better_nested_set.rb in the lib folder of the BetterNestedSet plugin with the following:

def parents    acts_as_nested_set_options[:class].find(:all, :conditions => "(#{acts_as_nested_set_options[:right_column]} <> #{acts_as_nested_set_options[:left_column]} + 1)", :order => "#{acts_as_nested_set_options[:left_column]}")  end    def leaves    acts_as_nested_set_options[:class].find(:all, :conditions => "(#{acts_as_nested_set_options[:right_column]} = #{acts_as_nested_set_options[:left_column]} + 1)", :order => "#{acts_as_nested_set_options[:left_column]}")  end

Or if you're savvy you can just apply the patch I created that includes these methods along with documentation and tests:

  • download the patch
  • move the patch to the root of your BetterNestedSet plugin
  • patch -p0 < leaves_and_parents_class_methods.patch

I've also added the patch as an enhancement to the BetterNestedSet trac.

On a recent project when I was using the BetterNestedSet plugin to manage a large hierarchal set of data, I encountered a problem that required me to find all of the items in a nested set that had children and those that didn't. In nested set terms I wanted: all 'parent' nodes and all 'leaf' nodes that exist within the 'tree'.

If you want to do this through the current BetterNestedSet interface you might be tempted to do something like this:

Categories
Author

As much as we all strive to write perfect, semantic XHTML that can be styled entirely independently, the reality of browser compatibility and even our own creative choices often leads to design refactoring. Obviously in Rails one big help for this is the use of partials, making sure that you can change your markup in one place and it will be reflected for often-repeated content. But what about for lower-level, underlying layout structure? Nested partials quickly become a mess to deal with, and traditional helpers don't always offer the flexibility and intelligence that is needed to get the job done.

Enter block-accepting helpers. These allow you to wrap markup around content without the ugliness of a my_thing_start and my_thing_end. With a little more work, they can also provide an intelligent layout structure that requires minimal (and beautiful) code in the view. Let's start with a simple example. Lets say that most, but not all, of the pages in my app have a similar container and title. Creating multiple layouts using partials for everything just to add or not add a couple of lines of code is way too heavy. On the other hand, my designers want the flexibility to change how the container is represented in markup, so I can't just throw the markup into each action. Here's the markup I want (for now):

<div class='main_container'>      <h3><!-- Some Title --></h3>      <!-- Some Contents-->  </div>

This is obviously pretty basic, and wouldn't be a big deal to change if the design changed, but this is just an example. If you're dealing with some kind of nested div rounded corner solution, or any number of other necessary CSS/markup hacks to get the look you desire, it could become quite a chore. So how do we create our DRY helper? Primarily through the use of the concat method in the ActionView::Helpers::TextHelper module. Here's my helper (just put this in either the relevant helper or ApplicationHelper:

def main_container(options = {}, &block)    concat("<div class='main_container'>",block.binding)    concat("<h3>#{options[:title]}</h3>",block.binding) unless options[:title].blank?    yield    concat("</div>",block.binding)  end

So that wasn't so bad, was it? Now in our views all we have to do to get our main_container is:

<% main_container :title => 'My Page Title' do %>      <p>We can put whatever we want here, and it will appear inside the container.</p>  <% end %>

Cool, huh? There are other resources that dig much deeper into blocks, procs, and the ruby wonderfulness going on behind the scenes, but this is purely a functional demonstration. Suffice to say that placing a &block (or &proc or whatever you want to call it) as the last parameter of a method allows that method to accept a block and later yield to it. The yield statement works much the way it does in layouts, passing code execution for a time and then getting it back when the yielded code is finished.

Do make note that, like form_for, you do not use the <%= but just <% when declaring your block. This is because you aren't returning anything, but rather directly concatenating code onto the binding passed when you make the block call.

Now that was certainly useful, but doesn't really have that 'wow' factor that really makes you appreciate a new way of doing things. Let's take a stab at another common problem in app design: menu systems. Using block-accepting helpers and introducing the concept of a builder class, we can build menus intelligently and easily.

The implementation you are probably already familiar with of this type of class is the FormBuilder used in form_for. We will take that same concept and apply it to menus on a web application, taking care of a number of common headaches associated with menus. Here's the whole enchilada, and we'll go through it piece by piece. This code should be dropped into a helper:

def menu(options = {}, &block)    id = options[:id] || 'menu'    concat("<div id='#{id}'><ul>",block.binding)    # we yield a MenuBuilder so that specialized methods     # may be called inside the block    yield MenuBuilder.new(self)    concat("</ul></div>",block.binding)  end    class MenuBuilder    def initialize(template)      # by passing in the ActionView instance, we gain       # access to all of its helpers through @template      @template = template      @action_count = 0    end      def action(name, options = {}, html_options = {})      # create a local array for the classes we will be tacking on to the list item      classes = Array.new      # add the 'current' class if the current page matches the link options      classes << 'current' if @template.current_page?(options)      # add the 'first' class if this is the first time we've added an action      classes << 'first' if (@action_count == 0)      @action_count += 1      "<li class='#{classes.join(' ')}'>#{@template.link_to(name, options, html_options)}</li>"    end  end

So that should look at least somewhat familiar, right? Here's a sample implementation so that we can talk about what's going on:

<% menu do |m| %>    <%= m.action 'Home', home_path %>    <%= m.action 'Blog', blog_path %>    <%= m.action 'Account', edit_user_path(current_user) %>  <% end %>

So in just a few readable lines of code, we've done all we need for a pretty complex menu. However, because of our helper, all of the complexities are going on behind the scenes! So let's talk about our helpers. The actual helper that we call is very similar to the one we made earlier with one difference: rather than yielding with no parameters, we yielded a MenuBuilder object, which was then called in the yielded code to create menu actions. A builder can be used when there needs to be state information or more complex logic than simple helpers can provide.

In this case, we wanted to make sure that an action was marked as the first action if it was indeed the first to be called. By implementing an instance variable to count the number of actions that had been called, we are able to do this with ease. Additionally, if we ever wanted to change how the menu items were rendered, all of the changes are completely contained in the helper and builder, leaving the views unchanged.

I've found it a useful practice to stub out block-accepting helpers for any markup that I think I'll be using frequently at the start of an application. This gives the developers a chance to keep going while the design can evolve on a completely separate track. Additionally, it creates some fantastically readable code in the views.

Categories
Author

Dave Naffis demonstrated Intridea's Photo Greeting Card Application in-front of a technology audience at the Facebook Developer Garage event in Washington DC. This event was sponsored by Facebook and the local tech companies. The demo followed a lively discussion of new features and enhancements. Kudos to Pradeep for developing the app in one weekend.

Intridea is developing several facebook apps for large corporations to extend the corporate brand into facebook's social graph.

Categories
Tags
Author

Over the past few days I've been diving into Selenium, an automated functional testing tool for web apps. It's pretty slick - in fact, like most of the technologies I've been using over the past two years, it does so much for you that the struggle always ends up being a matter of getting out of its way and letting it do its thing. So I'm gonna throw out some pointers on using Selenium within the Rails testing framework via the selenium_on_rails plugin; the only caveat I'll mention is that this post is especially geared towards the newbie wading into a project with pre-existing selenium tests. So I'm focusing on how you can get started with writing tests and integrating them into what's already there.

Open up firefox and install the Selenium IDE extension. This allows you to record your test by simply using the browser. The IDE keeps track of where you click - just make sure the record button is on. Go ahead and click through your test application and watch as the IDE records your actions.

Now you need to go into your selenium_on_rails plugin area and edit config.yml. In the browser config area, make sure it's pointing to your browser binary. For example, I kept most of the defaults, but made sure the following lines were there, uncommented:

environments:
- test
browsers:
firefox: '/Applications/Firefox.app/Contents/MacOS/firefox-bin'

Next, especially if this is a project with existing tests, make sure you've installed the right user extensions. These are prefabbed actions for doing things like logging in via javascript. In my project I found this file in:

vendor/plugins/selenium_on_rails/selenium_core/scripts/user_extensions.js

All you need to do is point the IDE at this file by opening the IDE window and navigating in the top menu to "Options > Options > General tab". Put the path to user_extensions.js in the input box entitled "Selenium Core extensions (user-extensions.js)".

OK, so let's take a look at the existing selenium tests. They're probably in test/selenium. If there's subdirectories under that, these are probably test "suites". For example, in the project I'm working on, they're organized depending on which type of user the test is geared towards: user or admin. The actual test scripts can be recorded in a variety of formats; mine are all HTML tables, where each row is a step in the process.

So let's get to recording tests. First, start your server in the test environment:

mongrel_rails start -e test

The whole premise of testing is verifying the response to an action. In Selenium, this is accomplished via assertion statements. The IDE makes this elementary: when you've reached a page on which you need to verify the output, just highlight the text and right click. At the bottom of the popup menu, several approaches to verifying the text are mentioned. I don't understand all the "selenese" yet but there's simple commands like "assertText" that ensure a particular passage is included on the page - that should get you started.

So you've recorded the steps necessary - now click "File > Export Test As" and save it in the correct test directory in the format you wish (such as HTML). Now you should be able to run this test via rake test:all. That's it!

Categories
Author

Here's a quick way to add Subversion notification for Campfire using Tinder.

Create svn-campfire.rb with the correct username and password:

  #!/usr/local/bin/ruby  require 'rubygems'  require 'tinder'    svnlook = "/usr/local/bin/svnlook"      campfire = Tinder::Campfire.new 'campfiresubdomain'  campfire.login 'user@example.com', 'password'  room = campfire.find_room_by_name('room name')  room.join    if ARGV.size > 1    revision = ARGV[1]    path = ARGV[0]    # we're using this for multiple svn repos so parse the project name from the path    project = ARGV[0].gsub("/home/user/svn/", '')        author = `#{svnlook} author -r #{revision} #{path}`    paths  = `#{svnlook} changed -r #{revision} #{path}`       log    = `#{svnlook} log -r #{revision} #{path}`    message = [log,paths].join("n").strip    url = "Changeset ##{revision} by #{author} (http://trac.domain.com/trac/#{project}/changeset/#{revision})"      room.speak(url)    room.paste(message)  else    room.speak(ARGV[0])  end    room.leave

Add this to your SVN post-commit hook:

  /usr/local/bin/ruby /path/to/svn-campfire.rb "$1" "$2"

Here's a quick way to send emails to campfire. Create an email address to use for sending messages to campfire and then create mailer-campfire.rb with your domain, usernames and passwords:

  #!/usr/local/bin/ruby  require 'rubygems'  require 'action_mailer'  require 'tinder'  require 'net/pop'    # setup an email address to use for campfire  Net::POP3.delete_all("domain.com", nil, "user+domain.com", "password") do |m|    campfire = Tinder::Campfire.new 'campfiresubdomain'    campfire.login 'user@example.com', 'password'    room = campfire.find_room_by_name('room name')    room.join      begin      message = TMail::Mail.parse(m.pop)            subject = message.subject if message.subject      sender = message.from.first if message.from      body = message.body if message.body            room.speak("I've received an email from #{sender} with the subject '#{subject}'")      room.paste(body)                    rescue Exception => e    end                  room.leave  end

Then create a cron job to fire this off every minute:

  * * * * * /usr/local/bin/ruby /home/path/to/mailer-campfire.rb

We also use it to remind us of daily standups:

  #!/usr/local/bin/ruby  require 'rubygems'  require 'tinder'    campfire = Tinder::Campfire.new 'campfiresubdomain'  campfire.login 'user@domain.com', 'password'  room = campfire.find_room_by_name('room name')  room.join  room.paste("Time for daily standup.nWhat did you do yesterday? What are you doing today? Any roadblocks?")      room.leave

Our cron job fires it off every weekday at 2pm.:

  0 14 * * 1-5 /usr/local/bin/ruby /home/path/to/status-campfire.rb

Next step, create a Jabber gateway for Campfire using Tinder.

Categories
Author

At Intridea, we’ve been busy little beavers working on a couple of hush-hush facebook apps. Needless to say, you will be hearing about those quite soon. But first, a little discussion about Rails plugins for the Facebook F8 API is in order.

The most popular Rails plugin for the Facebook API is RFacebook. The core implementation of RFacebook relies a lot on Hpricot and method_missing (covered earlier in this post) to map the XML results from Facebook to Ruby objects.

There are a few goodies in RFacebook: SSH tunnelling, URL rewriting, and a nice debug panel that displays right on the facebook canvas. RFacebook is becoming more and more mature by the day, but unfortunately maturity sometimes does not equal usability or productivity (by Rails standards, of course). My main issue with RFacebook however, is the convoluted MVC design. For example, facebook session calls are made through a fbsession object. However, this object is accessible only within the controllers, and not the models. Moreover, fbsession objects use method_missing to transfer methods not defined in the ruby code over to Facebook, and so there is no concrete mapping between functions and their variables—it makes things like passing partials instead of strings as parameters for session calls in the controller more difficult, and lo and behold, we’re forced to use the ugliness that can only be mentioned as “html-code-in-the-controller”. Small things surely, but we use Rails and Ruby to “increase productivity and happiness”, and any libraries that have the possibility of being heavily used should be written with such things in mind.

A new contender is Facebooker written by Chad Fowler. He outlines the design points (most of which are vehement arguments against RFacebook’s way of doing things), in a very nice post. A quick look at the code (which is all I have done so far, more to come later) suggests that this is really a very concrete API, that maps functions to non-method_missing functions. However, it does have a bit of a learning curve right now and is well below RFacebook in terms of immediate user-friendliness, which is to be expected since it is still under development and has had no public announcement besides that blog post. More details as we move forward..

Running a quick search on ‘rails facebook plugins’ gives me more results today than it did a few weeks ago, so it seems apparent that there are a few more plugins left that I have missed. Along with that, the new release of Facebook’s Data Store will most definitely bring forth atleast a few more new ones.

Categories
Author

If you've used attachment_fu (introduction here) in your Rails applications, you probably love its simple nature and its S3 integration. You may love less its very sparse documentation. When working on a project recently, I needed to save items to a path based on the owner of the attachment model, not the model itself.

The first attempt involved adding inline instance method calls to the :path_prefix option passed into has_attachment. This failed because has_attachment works on the class level, not the instance level.

After digging deeper, I found that the only thing one needs to do in order to change the path of a save in attachment_fu is to have a defined base_path method in your model. In the example of a user-based system with an avatar stored for each user, this might be a useful way to define your base_path:

class Avatar  :image,                 :storage => :s3,                 :resize_to => '150x150'  				   	    def after_save      # Delete any existing avatars they have uploaded.      Avatar.find(:all, :conditions => ["user_id = ?",self.user_id]).each do |ava|        ava.destroy unless ava.id == self.id      end    end          # Here we define base_path and therefore save to a custom location    def base_path      File.join("users", self.user.login, "avatar")    end  	    validates_as_attachment  end

This is a very simple example, but this provides a model of an avatar that will save to a folder under users/theusername with the filename the same as . For even further customization (including the filename), dig into the full_filename method in your storage solution of choice, and override in a similar fashion.

Just a quick Rails tip to help you along your attaching way.

Categories
Author

As a Rails developer currently stuck using a Windows environment, I've run into a number of problems trying to use gems with native extensions such as RMagick, etc. Fed up with taking twice the time to accomplish the same thing, I decided to get a Linux-based server up and running locally. Since I don't have a dedicated box lying around, I decided to try virtualization. The end result is a virtualized Linux server into which I can shell, build apps, and test either locally or remotely.

Acquiring the Appliance

The first thing I needed to do was get The VMware Player. This freely available virtualization solution is widely used and allows for easy setup of virtualized operating systems of any kind. Download and install VMware Player using normal options.

Next, I needed to get my base appliance. While there is an existing Rails Appliance for VMware Player, I found that it didn't give me the flexibility I needed in installing custom gems and caused more problems than it eased. I decided to go with a clean install of Ubuntu Server on top of which I would add everything I needed. Get the Feisty Fawn distro I used here.

Once your distro has finished downloading, extract into desired location and run using the VMware player. The distribution linked in this article has no root, but an account called notroot with a password of thoughtpolice. You should obviously either change the password or create a new account for yourself immediately for security purposes.

Get Rails Up and Running

Now it's time to install ruby, rubygems, rails, and everything else you might need or want for your new web distribution. Note that I am not setting up an elaborate system, just the bare basics needed to run and test rails applications.

Next we're going to set up our distro with all of the things we'll need for a basic Rails development box. Do the following in your command shell (References: urbanpuddle.com, rails wiki):

  sudo apt-get update  sudo apt-get install build-essential ruby rubygems irb1.8 ri rdoc ruby1.8-dev mysql-server libmysql-ruby libmysql-ruby1.8 libmysqlclient15off mysql-client-5.0 mysql-common mysql-server-5.0 rdoc1.8 ri1.8 ruby1.8 libmysqlclient5-dev  gem install rails --include-dependencies  gem install mongrel --include_dependencies  gem install mongrel_cluster  echo 'export PATH=$PATH:/var/lib/gems/1.8/bin' >> ~/.bash_profile  source ~/.bash_profile

That giant block of goodness builds and installs everything you need to get started with your development.We're installing Ruby, RubyGems, a MySQL server, and the associated development libraries that will let us build native extensions such as the mysql gem if desired.

Now that we have the basics, you should be able to pop open a directory (I used /var/www) and create your rails application skeletons. Gem installations should work as normal, and you now have a very basic Rails development environment.

SSH and NAT

You may want to be able to shell into your new virtual machine. The first thing you will need to do is install an SSH server:

sudo apt-get install openssh-server

The trickier part comes in configuring the virtual machine's networking to allow external access. First you need to find out the internal IP for your virtual machine. In your shell, type ifconfig and write down your IP. Now, if you are running VMware Workstation, open the "Manage Virtual Networks" item in the VMware Start Menu folder. If you are running the free VMware Player, open up vmnetcfg.exe in your install directory.

There's a lot to this program, but what you want now is the NAT tab. Make sure NAT service is started then click the "Edit..." button. Click through to "Port Forwarding...". Now you need to add port forwarding for any ports you may want accessible outside the virtual machine. To add a forwarded port, go to add and fill in the IP address you wrote down from ifconfig.

I forwarded port 22 for SSH and ports 3000-3005 for my rails development apps. Once you've added all of the ports you wish to forward, hit "OK" and "OK" again and "OK" again. You should now be able to shell into your VM using PuTTy or the like, transfer files with an SCP program such as WinSCP, and visit your Rails apps live once you run a server with script/server.

There's infinitely more to go over in the world of server configuration, but this is a quick and easy way to get a Linux environment on a Windows box.

Categories
Author
Subscribe to