Tag Archive | rails

Import a gemset without bundler

Here’s the scenario…

I’m trying to get a Rails 2.1.1 application up-and-running on my Mac (Lion). The application uses Ruby 1.8.7-p334. Bundler is not used so there’s no chance of doing a bundle install… drat!

I have a gemset export from another developer’s machine, which was created by doing this:

rvm gemset export my_app

That gives me a file which looks like this (truncated for brevity)…

# my_app.gems generated gem export file. Note…
actionmailer -v2.1.1
actionpack -v2.1.1
activerecord -v2.1.1
activeresource -v2.1.1
activesupport -v2.1.1

So, in theory it should be as easy as pie to import this gemset like this:

rvm gemset import my_app

Wrong!

The main problem arises when you install these gems, because the dependencies are not managed properly (this is what bundler was created for). So you end up with multiple versions of gems installed.

Pain.

The trick now is I need to be able to do a diff between my currently installed list of gems and the desired list given to me by the other developer. You could do this manually, but I’m far too lazy for that…

So, I created a little ruby script which will accept two files to be used for the diff operation, together with a third optional argument depending on whether I want to install or remove the gems.

Here’s the script…

#!/usr/bin/env ruby

unless ARGV.count >= 2
  puts "Please provide two files to perform diff..."
  exit
end

def load_file file
  arr = File.readlines(file).map(&:chomp).compact
  arr.shift if arr.first =~ /^#/
  arr
end

f1, f2 = load_file(ARGV[0]), load_file(ARGV[1])
command = ARGV[2] || 'install'

((f1 - f2) + (f2 - f1)).uniq.each do |gem|
  puts "gem #{command} #{gem}"
end

Save this into a file called file_diff.rb and make the file executable:

chmod +x file_diff.rb

Now, it’s easy to get the exact gems installed by following these simple steps…

./file_diff.rb file1 file2 uninstall > uninstall.sh
chmod x+ uninstall.sh
./uninstall.sh

And that’s it! You should now have the same gems in your gemset that your friend has in his gemset, as per his exported list.

Setting up Ubuntu 11.10 for Rails development… Just Right!

Further to my previous post on how to setup Ubuntu 11.10 for Rails development, I have now created a bash installer script to automate the whole laborious process for your pleasure… well it’s for my own pleasure really, but I like to share!

There are two installer scripts:

  1. Ubuntu user will setup your Ubuntu 11.10 environment will all the usual goodies you normally should install after a clean install / upgrade.
  2. Rails developer will setup your Ruby environment using RVM, along with all the supporting things that you will need to get up and running in no time.

The installers are updated regularly so check the git pages for full details, but some of the key things that are installed are…

The Ubuntu user installer will hook you up with these (among others)…

  • Medibuntu repositories
  • Ubuntu Restricted Extras
  • Configuration Editor (dconf-tools)
  • Compiz Config Settings Manager
  • Synaptic
  • Terminator
  • GNOME Tweak Tool
  • VLC
  • Jupiter
  • Caffeine
  • Web apps and Sushi file previewer
  • Simple LightDM Manager
  • Sysmonitor App Indicator
  • Dropbox
  • OpenJDK (Java 7) – optional

Some of the things the Rails developer installer will setup are…

  • SSH key – optional
  • Essential Ubuntu libraries
  • Ruby 1.8.7 from Ubuntu repostories with additional libraries
  • Git and Git Gui
  • MySQL 5.1 with admin GUI tools
  • MongoDB 2.0.1 – optional
  • ack
  • ImageMagick
  • RVM (Ruby Version Manager) with these rubies: 1.8.7 stable and 1.9.2 stable

Head over to the git repository for instructions on how to run the installers and also for more details about what it actually installs:

https://github.com/edjames/just_right

Simples.

Setting up Ubuntu 11.10 for Rails development

This method is depricated and has been replaced by an automated installer. See this post for more details:
Setting up Ubuntu 11.10 for Rails development… Just Right!

The setup for Ubuntu 11.10 almost identical to the 11.04 setup. A few libraries have changed but otherwise it’s exactly the same.

As before, I like to have a system Ruby installed. This has always been a precautionary measure but has saved me plenty of pain with past installs.

sudo apt-get install build-essential openssl ri ruby ruby1.8 ruby-dev rake libruby1.8 git-gui gitk libxslt1-dev libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison

Then install RVM (see the RVM website for the latest installation instructions).

$ bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)

Then run the following command, and… READ THE NOTES!

rvm notes

Make sure you read the RVM post-installation notes. You will get an updated list of OS dependencies and instructions on how to modify your .bash file. If you don’t do this you will probably drive yourself crazy trying to get RVM to work. You will fail.

Finally, install whatever rubies you want:

rvm install 1.8.7
rvm install 1.9.2
rvm install 1.9.3

Finally, install MySQL (and the MySQL GUI tools)…

sudo apt-get install mysql-server libmysqlclient-dev libmysql-ruby mysql-admin

Happy coding!

Easy grid tables and forms using pivot_table

One of the most frequently requested features I’m faced with is the ability to display tabular data in a grid which resembles an Excel pivot table. If you’re not familiar with the pivot table concept, take a look here.

I have yet to find a gem that makes this easy, so I’ve created my own. Introducing pivot_table.

The gem is self-explanatory, but still fairly young, so feel free to fork and update to suite your own needs.

Here’s a screenshot of what you can easily accomplish with this gem.

The gem will evolve along with my application’s needs, but I’d appreciate any additional help or feedback.

Simples.

ActiveResource: How to avoid “undefined class/module” exception

I use webmock to stub external endpoints in test and development mode. It’s a fantastic gem and I cannot recommend it highly enough.

I ran into some problems this week using it together with ActiveResource (AR). We were allowing our test-driven approach to define the response of a yet-to-be-built API method. We were defining the API response in YAML, and then when setting the webmock stub, converting the YAML to json. Nothing too fancy there.

The problems started happening when we added a nested level to our YAML file. When AR loads a response, any nested levels are created as nested AR classes, and our app was bombing out when we introduced this nested level. We kept getting “undefined class/module …” exceptions.

Here’s what our YAML looked like:

:quote_id: 102
:detail:
  :premium: 100.00
  :total: 145.00

See the nested detail level? When AR receives the json version of this response, the AR object will have quote_id as an instance method. But, it will have premium and total as instance methods on a nested Detail object.

Why was this an issue for us?

We receive the API response and need to persist it in our application, but we want to do this persistence using the session (and ActiveRecord session mind). It’s not a good idea to put complex objects into the session store, so before doing that we use Marshal to serialize the object. Similarly, when retrieving the object from the session, we then need to deserialize the object before we can use it. It’s at this point that things go wrong because AR will not know about the nested class within the object. It will fail.

The solution is quite simple, although not entirely flexible in that you do need to know about which nested classes you will be handling.

I created two class methods to deal with the serialization. Serializing the object is easy. Deserializing requires us to use the find_or_create_resource_for method, which can be found in the ActiveResource::Base class. It’s used internally by AR to overcome this exact issue.

Here’s my AR class (simplified for brevity). Note that the single-item list of nested classes contains the Detail class, as defined by the nested level in my YAML file above.

class PaymentDetail < ActiveResource::Base
  self.site   = Rails.application.config.special_api
  self.format = :json

  NESTED_CLASSES = %w(Detail)

  def self.stringify_quote obj
    Marshal.dump obj
  end

  def self.load_quote str
    # preload nested classes to avoid an ActiveResource undefined class exception
    NESTED_CLASSES.each { |klass| PaymentDetail.new.send(:find_or_create_resource_for, klass) }
    Marshal.load str
  end

end

How does this help me?

This will allow you to easily persist any AR object in a session (or cache) for later use, which is especially useful for API’s that are read-only. It means you can persist the state of an AR object even when the source of that object – the external API – does not allow the changing of that state.

Hope this saves someone some time!

Freeze your data in time using serialization

I have a use case in which my user wants to be able to create an instance of a model which has several has_many relationships. Easy enough.

However, these has_many relationships will change over time, and any future change should not have an any impact on any existing instances of my model. A little more tricky.

Let’s jump into an example. I have a FleetRoster, which is composed of a list of Trucks. Each truck belongs to a Transporter. I want to create a new FleetRoster by selecting the relevant Trucks. However, as a Truck can change from one Transporter to another, when I create my FleetRoster, I want this Truck-to-Transporter relationship to be captured so that when I generate a document from my FleetRoster it will show the correct relationships at the time of creation.

Here are my models:

class FleetRoster < ActiveRecord::Base
  serialize :data
  has_many :fleet_trucks
  has_many :trucks, :through => :fleet_trucks
end

class FleetTruck < ActiveRecord::Base
  belongs_to :fleet_roster
  belongs_to :truck
end

class Truck < ActiveRecord::Base
  belongs_to :transporter
end

class Transporter < ActiveRecord::Base
  has_many :trucks
end

The key line here is the first line in the FleetRoster model. I’m telling ActiveRecord to serialize the :data column before a save operation, and what this allows us to do is store something like a hash in this column.

Then all we need to do is prior to saving a new instance, gather all the relevant information (Trucks, Transporters etc) including their relationships at the time of processing, and store this information in a normal hash. Next, modify your view to render information from your hash instead. Finally, remove the option to edit these records.

You will then effectively have created immutable records which preserve all the relationship information.

The benefit of doing this instead of generating and saving documents is that should your document design change, you don’t have a whole load of documents using the old layout. After all, we’re only interested in the CONTENT, not the LAYOUT. It also means that everything related to your documents can stay in your database (the content) and your models (the layout and format).

Step through your cucumber features interactively

NOTE: This is probably only useful for features that run in browser mode i.e. NOT headless. Using Rails 3 and Capybara, these would be features tagged as @javascript.

Do you find yourself using the save_and_open_page method to debug your cucumber features? Or how about raising exceptions to break the scenario execution? I guess it works, but not very elegant…

One easy way to pause the scenario execution after each step is to use the cucumber callbacks.

Start by creating a hooks.rb file in your features/support folder. You can name the file whatever you want, but it must have a .rb extension. Then add the following snippet to your new file:

AfterStep('@pause') do
  print "Press Return to continue..."
  STDIN.getc
end

What we’re doing here is using the AfterStep callback to execute our code after each cucumber steps has finished. The parameter is telling cucumber to only do this for features that have the @pause tag. We then wait for a carriage return from the console before moving to the next step.

Now all you have to do is tag a feature with @pause and you will have to press Return after each step to walk through the scenario. This makes debugging a snap when you’re using something like Firebug etc.

Try it out for yourself.

Creating AJAX forms with Rails 3 and jQuery

I’ve been digging around for a few days trying to find a good example of a fully-functional ajax form using Rails and jQuery. Rails 3 provides a very nice form helper to make forms submit asynchronously, by simply adding this to your form declaration:

:remote => true

Fine. That handles the ajax form submission. But then what? What if you want to do other things after the submission has happened? What about custom ajax events as per the jQuery API? What about response messages and errors?

So I set out to make a fully-functional demo which has all the CRUD operations as ajax submissions. What I wanted was to be able to create, edit and delete all from the index listing without having to navigate to another page. I’m not going to list all the code here because it’s all available in the public repo (github.com/edjames/ajax_forms), but some explanation is needed, so I’ll highlight a few interesting things.

The Model

I’ve added some simple validations to the model to illustrate how we could handle these in ajax form submissions. You want your users to know when something cannot be created/saved/deleted, don’t you? More on this later…

The INDEX Action

Nothing out of the ordinary here, but in the view we have extracted the display code for each band into a partial called _band.html.haml. This is important because we will reuse this partial for the create and update actions.

The NEW Action

When a user clicks the “New Band” link, all we want to do is append the form for creation to the list of bands, rather than navigate away from the index page. To do this we bind a jQuery function to the “click” event on the link which submits an ajax request to the “new” action. All the controller does is render a partial which contains the html form. We catch this response in jQuery and append it to our list.

The CREATE Action

The form is submitted via an ajax request. This is done by simply adding a single directive to our form declaration:

:remote => true

Notice that our controller action only responds to js requests, meaning the views are simply JavaScript snippets which are executed when they are rendered.

If the creation is successful, we render the create.js.haml view. The JavaScript in the view hides the form and then appends the newly created band’s html to our list using the _band.html.haml partial I mentioned previously.

If the creation failed, we render the _error.js.haml partial which simply alerts all the error messages on our object. In this case it will be validation failure messages.

The EDIT Action

As with the NEW action, we also bind a jQuery function to our “Edit” links. This function will hide the read-only row in our list, and insert the form html into the list, simulating an in-place edit.

The UPDATE Action

The same as our CREATE action, except instead of simply appending the new read-only html to our list, we now overwrite the existing band’s read-only html with the new content, and then remove the form from the DOM.

The DELETE Action

Following the same pattern, we again render the expected delete.js.haml view on a successful deletion. The JavaScript in the view will delete the relevant band from our list.

Custom AJAX events

In the application.js file I have also bound functions to the custom ajax events the fire both before and after an ajax request. All the do is log to the console, but it’s useful to see which events fire and when they fire. Using Firebug you can easily see what this looks like…

Why do you use divs instead of a table?

I use divs because it makes the html fully compliant. Using a table would mean wrapping a TR element with FORM tags, which strictly speaking creates non-compliant html. Although most modern browsers will handle this without any problems, it’s always advisable to err on the side of safety.

In closing…

I hope you find this post and the accompanying demo app useful. I spent a few days playing with various options, digging into the jQuery API, and scratching around on the web to find something that worked. In the end I had to do this myself to prove the idea.

Make sure you check out the application code, paying particular attention to the JavaScript that exists in both the templates and the application.js file.

Setting up Ubuntu 11.04 for Rails development

The setup for Ubuntu 11.04 almost identical to the 10.10 setup.

First, install the necessary packages and a system Ruby (1.8.7). RVM will ignore the system installed Ruby, but in my experience you will save yourself a lot of hassle by having a system-installed Ruby.

sudo apt-get install ri ruby ruby1.8 ruby-dev rake libruby1.8 zlib1g-dev libssl-dev libreadline5-dev libncurses5-dev build-essential curl git-core git-gui gitk libxml2 libxml2-dev libxslt1-dev bison autoconf

Then install RVM (see the RVM website for the latest installation instructions).

bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

Then run the following command, and… READ THE NOTES!

rvm notes

Make sure you read the RVM post-installation notes. You will get an updated list of OS dependencies and instructions on how to modify your .bash file. If you don’t do this you will probably drive yourself crazy trying to get RVM to work. You will fail.

Finally, install whatever rubies you want:

rvm install 1.8.7-head
rvm install 1.9.2-head

Then install MySQL (and the MySQL GUI tools)…

sudo apt-get install mysql-server libmysqlclient-dev libmysql-ruby mysql-admin

Happy coding!

Setting up Ubuntu 10.10 for Rails development

The setup for Ubuntu 10.10 is a little different to the 10.04 setup. I seem to have to manually install quite a few more packages to get things moving. But as usual it’s easy enough once you’ve done it once…or a few times.

First, install the necessary packages and a system Ruby (1.8.7). RVM will ignore the system installed Ruby, but in my experience you will save yourself a lot of hassle by having a system-installed Ruby.

sudo apt-get install ri ruby ruby1.8 ruby-dev rake libruby1.8 zlib1g-dev libssl-dev libreadline5-dev libncurses5-dev build-essential curl git-core git-gui gitk libxml2 libxml2-dev libxslt1-dev bison autoconf

Then install RVM (see the RVM website for the latest installation instructions).

bash < <(curl -B http://rvm.beginrescueend.com/install/rvm)

Then run the following command, and… READ THE NOTES!

rvm notes

Make sure you read the RVM post-installation notes. You will get an updated list of OS dependencies and instructions on how to modify your .bash file. If you don’t do this you will probably drive yourself crazy trying to get RVM to work. You will fail.

Finally, install whatever rubies you want:

rvm install 1.8.7-head
rvm install 1.9.2-head

Then install MySQL (and the MySQL GUI tools)…

sudo apt-get install mysql-server libmysqlclient-dev libmysql-ruby mysql-admin

Happy coding!

Follow

Get every new post delivered to your Inbox.