Skip to main content

Mobomo webinars-now on demand! | learn more.

Today Intridea launched the private beta of acts_as_community, a community site for Ruby and Rails developers.

acts_as_community is a place for Rubyists and Rails developers to gather and interact. Our hope is to bring the community closer together in collaboration and communication so that everyone can benefit from others' experiences.

If you would like to join email us at aac@intridea.com for the beta key.

Categories
Author

Often times in an application you might want to know how many of a given model were created today. Rather than writing a custom method for each model, let’s keep it DRY and extend ActiveRecord:

class ActiveRecord::Base   def self.new_today     if self.new.respond_to?(:created_at)       self.count(:all, :conditions => "created_at > (NOW() - 60*60*24)")     else       nil     end   end end

This will return the number of records created in the last 24 hours by calling the model with new_today (e.×. User.new_today). It will return nil if the model does not respond to the created_at Rails timestamp attribute.

Categories
Author

I’ve been working a lot with seed data in my applications lately, and it’s obviously a problem that can be pretty aggravating to deal with. I ultimately liked the db-populate approach the best with the addition of the ActiveRecord::Base.create_or_update method. My one problem with it is that it’s based entirely on fixed ids for the fixtures, which is a pain to deal with when loading up your attributes from arrays. Here’s an example of what I was doing:

i = 1  { "admin"     => ["Administrator", 1000],    "member"    => ["Member", 1],    "moderator" => ["Moderator", 100],   "disabled"  => ["Disabled User", -1] }.each_pair do |key, val|   Role.create_or_update(:id => i, :key => key, :name => val[0], :value => val[1])   i += 1 end

I really don’t like having to put the i in there to increment up. Not only is it messier code, but it would be dangerous if I wanted to move around the roles. I also don’t want to have to have an id explicitly in each entry since I really don’t care what the id is. So I thought I would hack up a better solution for this create_or_update scenario and this is what I came up with:

class << ActiveRecord::Base   def create_or_update(options = {})     self.create_or_update_by(:id, options)   end      def create_or_update_by(field, options = {})     find_value = options.delete(field)     record = find(:first, :conditions => {field => find_value}) || self.new     record.send field.to_s + "=", find_value     record.attributes = options     record.save!     record   end      def method_missing_with_create_or_update(method_name, *args)     if match = method_name.to_s.match(/create_or_update_by_([a-z0-9_]+)/)       field = match[1].to_sym       create_or_update_by(field,*args)     else       method_missing_without_create_or_update(method_name, *args)     end   end      alias_method_chain :method_missing, :create_or_update end

Basically, this allows me to call create_or_update with an arbitrary attribute as my “finder” by calling Model.create_or_update_by(:field, ...). To give it a little taste of syntactic sugar, I threw in a method missing to allow you to name a field in the method call itself. So now the code I wrote before can become this:

{ "admin"     => ["Administrator", 1000],    "member"    => ["Member", 1],    "moderator" => ["Moderator", 100],   "disabled"  => ["Disabled User", -1] }.each_pair do |key, val|   Role.create_or_update_by_key(:key => key, :name => val[0], :value => val[1]) end

This is much cleaner and prettier to look at, and also makes sure that it is keying off of the value that I really care about. This new create_or_update combined with db-populate creates the most powerful seed data solution I’ve yet come across.

Categories
Author

Intridea is pleased to announce the beta launch of VisualCV (http://www.visualcv.com). Intridea has been working closely with VisualCV for several months to develop their breakthrough site and bring it to market. VisualCV reinvents the paper resume into a dynamic career management tool by incorporating images, audio, and video alongside traditional resume content.

Intridea partnered with VisualCV because we believe their approach will revolutionize the way companies and professionals interact. Using cutting-edge Internet technologies, we worked with VisualCV to build a unique platform that delivers highly interactive user experience as well as a secure mechanism for sharing resume content. VisualCV partnered with Intridea because of the national reputation we've earned for our agile Ruby on Rails practices.

Check out www.VisualCV.com now

[UPDATE]

VisualCV has been generating a lot of media buzz so far - check out some of the coverage below:

Categories
Author

I recently had to look over some code that was returning inconsistent results. I was able to fix the code with a few minor changes, but it was still very hard to follow. Take a look:

    def audit_self      # what level the charts was actually coded for      actually_coded = self.cpt_code.code.last.to_i              # determine if elements PASS -> 0, FAIL -> 1, or PASS and undercoded -> -1      self.history_result  = pass_or_fail_elements( actually_coded, self.history_levels )      self.hpi_result      = pass_or_fail_elements( actually_coded, self.hpi_levels )      self.ros_result      = pass_or_fail_elements( actually_coded, self.ros_levels )      self.organ_result    = pass_or_fail_elements( actually_coded, self.organ_levels )      self.mfs_result      = pass_or_fail_elements( actually_coded, self.mfs_levels )      self.mdm_result      = pass_or_fail_elements( actually_coded, self.mdm_levels )        if self.any_elements_failed?        self.overall_result = 1      elsif self.all_elements_undercoded?        self.overall_result = -1      else        self.overall_result = 0      end        min_level = 5      max_level = 0        for elem in ["history_levels", "mdm_levels", "hpi_levels", "ros_levels", "organ_levels", "mfs_levels"]        levels = self.send elem        max_level = levels[0] if levels[0] > max_level        min_level = levels[1] if levels[1]     

The first thing I did was to refactor the redundant categories into a hash. This is probably debatable if this is clever or just good DRY practice. This is really up to you - I found Hash#each was up to the task with a couple of send calls.

    CATEGORIES = {:history_levels => :history_result=,                  :hpi_levels => :hpi_result=,                  :ros_levels => :ros_result=,                  :organ_levels => :organ_result=,                  :mfs_levels => :mfs_result=,                  :mdm_levels => :mdm_result= }    

So we use Hash#each to run through the hash, run our pass_or_fail method, and then run the setter method to save the result. This should really be refactored further into its own method, but I want to focus more on the Enumerable#inject method for this article.

      def audit_self      # what level the charts was actually coded for      actually_coded = self.cpt_code.code.last.to_i              # determine if elements PASS -> 0, FAIL -> 1, or PASS and undercoded -> -1      CATEGORIES.each do |level, result|        answer = pass_or_fail_elements(actually_coded, self.send(level))        self.send(result, answer)      end       #snipped for brevity    

I refactored the code below to move that ugly for loop into its own method, and used inject instead, which seems much cleaner to me. By moving the code to its own method, writing tests for the logic flow becomes easier. It also makes it easier to track down these type of problems in the future.

            self.recommended_code = self.cpt_code.code.chop + minimum_coding_level.to_s            self.save    end        def minimum_coding_level      CATEGORIES.inject(0) do |result, level_method|        minimum = (self.send level_method[0]).first        result     

Ah, now the good part. Enumberable#inject is a very powerful tool, but if you aren't familiar with it, this code might feel a bit dense or unreadable. Inject allows us to loop through an array or hash - the variable named "result" contains the return value of our block each time. In our case, we are trying to find the highest minimum number. One thing that might look odd in this example is the level_method[0] - since we are using a hash, the key/value pair is set to level_method (as an array) and we just care about the key in this case.

Go forth young padawans and apply these learning to clean up your code and remove those for loops!

*Note:* I do realize this code could be refactored even more, but I really wanted to use this code as an example or how to use Enumerables, not so much about model method refactoring.

Categories
Author

After developing a number of applications, there were some actions I found myself performing over and over again with each new controller in each new application. With my DRY-sense tingling, I decided to do something about it and create a plugin to clean up some of those repetitive tasks that were vital but annoying to set up. Introducing Needy Controllers.

Needy Controllers takes care of your controllers’…well, needs. You can include stylesheets, javascripts, and memoized record helpers in your controllers and views with a single command, and even use filter-chain-esque options to specify and tailor to your needs. Basically, it simplifies the process of:

  1. Including stylesheets in your app on a per-controller/action basis
  2. Including javascripts on a per-controller/action basis
  3. Having helper functions to fetch records in common RESTful resource mappings

Installation

git clone git://github.com/mbleigh/needy-controllers.git vendor/plugins/needy_controllers

Usage

Styles and Scripts

To use Needy Controllers for styles and scripts, you simply call a “needs” option inside your controller like so:

class MyController < ApplicationController   needs :styles => :standard   needs :styles => :show, :only => :show   needs :scripts => :behave, :except => :show    def index     # this action will have access to the 'standard.css' stylesheet   end      def show     # this action will have access to the 'show.css' stylesheet     # in addition to 'standard.css'     # but will not have access to 'behave.js'   end end

Now that you have created your behavior and style chains, you need to include them in the view. Luckily, this is exceedingly easy! Just include :needs in your include and link tags like so:

<%= stylesheet_link_tag 'something', :needs %> <%= javascript_include_tag 'prototype', :needs, 'effects' %>

An additional benefit of the style and behavior chains is inheritance: namely, any controller that inherits from a controller with a stylesheet or javascript included using the above method will automatically have the same stylesheet and javascript included in itself. This allows you to easily set up includes that are scoped to your exact needs with as little work as possible.

Model Fetching

To use Needy Controllers for fetching records, you use it similarly, and it creates a helper:

class MyController < ApplicationController   # here's a standard problem   needs :record => :user, :from => :id, :as => :user end

The :from and :as options in this example are the defaults (:id for :from and :as defaults to the name of the record). This will create a method (“user” in the example)
that will be accessible both from the controller and from the view as a helper. It will find the record with a matching ID to the URL parameter associated with the :from option. Therefore if you had nested resources you could call it as such:

needs :record => :user, :from => :user_id

That’s pretty much it, just a few simple ways to make your coding life easier. As always, there is a Trac available for any issues and I would love to hear any feedback you might have.

Categories
Author

UPDATE

Click here for the latest on Beboist


The Beboist plugin provides a Rails interface to the Bebo Social Networking API.

The plugin was designed from the ground-up to be flexible enough to accommodate
any changes to the API, while at the same time providing a clean interface
that will be familiar to most Rails developers.

Setup

Ensure that the json gem is installed on your system and the Beboist plugin is installed in your vendor/plugins folder:

gem install json script/plugin install http://svn.intridea.com/svn/public/beboist</pre>

Generate your config/bebo.yml file using

script/generate beboist_settings</pre>

Fill in your appropriate app settings in config/bebo.yml. Ensure that your app name is right.

Generate the first migration for your users table using:

script/generate beboist_user_migration</pre>

Migrate your database using

rake db:migrate</pre>

In your application.rb, insert the following filters:

before_filter :reject_unadded_users before_filter :find_bebo_user</pre>

Write your app, and keep an eye on your logs to catch any possible error messages.

API Reference

The methods listed in the Bebo API Documentation are mapped to Ruby classes in the following manner:

users.get_info(uids => "1,2,3", fields => "first_name, last_name")   # BECOMES BeboUsers.get_info :uids => [1,2,3], :fields => ["first_name", "last_name"]

Notes

The Beboist plugin uses Bebo’s JSON API, and the ‘json’ gem to directly convert JSON objects to Ruby. It works with Rails 2.0+, but has not been tested on Rails 1.2. Check the README for more details, and file tickets at Intridea’s Public Trac

Categories
Author

Try as I might to avoid it, there comes the inevitable point in a project when I have to start doing browser compatibility. Plenty of people use VMWare Fusion or Parallels to run Windows and OS X side by side, but I find them both slow and unreliable when it comes to real testing scenarios, which leaves me with the necessity of creating a Windows development stack for Rails. After some considerable looking, I’ve settled on what I consider to be the “best” tools for the job – though they still fall short of the OS X equivalents.

  • Ruby/Rails: I use the full recommended Ruby distribution as opposed to InstantRails or similar to provide maximum flexibility and customization. I also use the MySQL Community Server for the database portion of my development stack.
  • Version Control: TortoiseSVN is a very easy to use SVN front-end, but my fingers have long since learned the console commands and continue to crave them, so I use the Apache 2.0 binaries for Windows to allow me to use SVN from the prompt.
  • Console: An absolutely indispensable application for me is Console. This open-source app provides tabbed command prompts in a much prettier interface with a number of other incredibly useful features. I highly recommend it.
  • Editor: This isn’t a slam dunk, but the closest thing to TextMate in Windows is, well, the app that was created to be TextMate for Windows. E Text Editor is very good (though in my opinion still too buggy to be called a 1.0) and comes the closest to approximating my Mac development environment. The heavier IDEs such as NetBeans and Aptana With RadRails are also viable options, but I like the speed and simplicity of E.
  • Debugging: Since the reason I end up in Windows in the first place is usually IE compatibility, I need tools to approximate the incomparable FireBug. For markup inspection, the most-helpful-least-hurtful I’ve found is Microsoft’s own Internet Explorer Developer Toolbar. Javascript debugging, the most heinous of all tasks, is made much less painful by the Microsoft Script Debugger. Don’t let the “Windows NT 4.0 and later” fool you, this is the most useful thing I’ve managed to find to get some kind of control over IE Javascript debugging.

These aren’t by any means the only tools available, and your needs/mileage may vary, but after finally getting this stack together I can develop in Windows without going into fits of hyperventilation and frustration. If you have your own indispensable tools for Rails development in Windows, I’d love to hear about them!

Categories
Author
Subscribe to