Iteratively Switching to Twitter Bootstrap

7 May

Here are some of my notes on an approach to iteratively switching a Rails app from Compass / Blueprint to Twitter Bootstrap / Compass

or view on https://gist.github.com/2628210

Upgrading to Twitter Bootstrap v2

16 Feb

Upgrading from Twitter Bootstrap 1.4 to 2 was a little bumpy, but I’m happy to be on the otherside of it. I hope they never change the number of cols in the grid again.

The upgrading to twitter bootstrap 2 docs are decent, but here are the few things I thought were missing, or just not obvious enough for me.

How to remove that arrow on the new dropdown menu:

.dropdown-menu:before, .dropdown-menu:after {
    content: none;
 } 

Form elements are now wrapped in .control-group, with .control-label for the label and .controls (instead of .input) for input.

Modal close link, now needs to include data-dismiss attribute – %a{:class=>”close”, :”data-dismiss”=>”modal”} ×

I used the twitter-bootstrap-rails gem and in upgrading there was an old coffeescript file bootstrap.js.coffee that didn’t get updated, it was creating js errors left and right until I manually deleted it. Then I had to manually add the source from the bootstrap.coffee

Update:
When I went to deploy this I got a rails precompile assets error – “rake aborted! Expected a color. Got: transparent”, this same issue. Turns out it was an issue with compass and the way it handles transparency. I updated my compass gem to this fork of compass, and it fixed the issue. Also in updating compass I found I had to also install the compass-rails gem to fix a sprocket issue, that manifested itself with the following error message: “Sass::SyntaxError: File to import not found or unreadable”

Digging into twitter bootstrap

22 Dec

I dove headfirst into twitter bootstrap a few weeks ago, here are some of my notes / findings.

How I use it – as part of a Rails 3.1 app, with SASS and Compass

Setup – pure CSS vs Less vs Sass

Twitter Bootstrap, Less, and Sass: Understanding Your Options for Rails 3.1

In my case we went with the twitter-bootstrap-rails gem – this lets us set variables in the bootstrap.less file and then we call another file that includes all of our sass. I spent a little time getting my custom variables in the bootstrap.less file to show up and then was a little disappointed with the amount of things you can do with the variables. A lot of the colors are hard coded in the source, even really obvious ones I suspect people would want to change, like filler color. In my opinion its almost so little, its a waste of time to get less up and running, might as well just overwrite static styles until better variables are available. Also from reading their response to issues on github improving the variable flexibility isn’t a high priority for them. (if you are already using less in your projects, then using some of the mixins may be helpful – I wanted to keep my project sass though, and found it easier to just create mixins on that side). All a matter of preference, I guess.

Note – if you are transitioning from using blueprint with compass make sure blueprint is really gone, I had some hidden places it was getting included and it does not play nice with Twitter Bootstrap.

Customizing the Look

For the most part this is self explanatory.

I did get tripped up in my attempt to overwrite the header and buttons in ie. The Compass mixin I used in my custom styles didn’t include the ie filter code which caused ie to fall back to the twitter bootstrap colors instead of just the background-color.  I added this mixin, sass mixin for ie linear gradient filter, and used it in addition to the compass gradient mixin.

So for exmaple:

.topbar-inner {
@include linear-gradient(color-stops($color_gray2, $color_gray));
@include ie-linear-gradient($color_gray2, $color_gray);
}

another way to handle it is to write a mixin that just kills the filter

@mixin kill-filter() {
 filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
 -ms-filter: none;
 }

Modals Baby

Pretty modals were one of the reasons we are making the switch to twitter bootstrap.

Great intro – http://paynedigital.com/2011/11/bootbox-js-alert-confirm-dialogs-for-twitter-bootstrap

I’d stay away from using .fade with the modals as it breaks links and buttons in chrome (discussion of the issue)

You can add the close modal x, just adding <a href=”#” class=”close”>x</a> in the modal header, it styles and just works, magic!

Get the Gist

I pulled together some of the styles and mixins I found helpful getting Twitter Bootstrap and Compass to be a full solution for me. Still a work in progress, add / comment on twitter_bootstrap_addons.scss

Thankful

24 Nov

In the spirit of Thanksgiving, I wanted to jot down a few things I am thankful for:

  • My wife – who’s humor and support I couldn’t live without
  • My family – they are awesome!
  • My job – I absolutely love what I do, I am so lucky to have the opportunity to work on something I believe in and with kind and super smart people.
  • My friends – I’m fairly certain they are the best friends anyone could have
  • My community – Somerville rocks
  • My home
  • My health
  • The open source community – without it my job would be impossible

I’m sure there are tons of things I forgot, but at least its a start! Happy Thanksgiving everyone!

displaying rss feeds in your rails app

4 May

Its very common to need to display recent news / posts from a blog outside of your Rails application. There are a few javascript widgets (like google reader) that make it easy to do that, but they suck from a performance standpoint. Its pretty easy to roll your own, here’s an example of how:

I got most of my info from http://rubyrss.com/

This is my home_helper.rb file

require 'rss/1.0'
require 'rss/2.0'
require 'open-uri'

module HomeHelper
  
  def blog_feed
    source = "http://feeds.feedburner.com/37signals/beMH" # url or local file
    content = "" # raw content of rss feed will be loaded here
    open(source) do |s| content = s.read end
    rss = RSS::Parser.parse(content, false)
    
    html = "<ul>"
    rss.items.each do |i|
    html << "<li><a href='#{i.link}'>#{i.title}</a></li>"
    html << "</ul>"
    html
    
    end
  end
end

and then in my view I can just write

<%= blog_feed %>

You’ll see that it loops through all of the items in the feed by default, if you want to limit that you can use .first()

rss.items.first(3).each do |i|

This needs a little clean up and error handling but its gives you a basic idea how how to get a feed parsed and displayed on your site.

i have some places in a database and I want to show them on a map – a quick tutorial using google maps api and rails

3 Feb

There is a tutorial over on the Google Maps API article page that shows how to use PHP/MySQL and the Google Maps API v3 to create a map that polls data from a database and shows as markers. I put together some notes to do the same thing using Rails.

First I created a migration to add a places table.

class CreatePlaces < ActiveRecord::Migration
  def self.up
    create_table :places do |t|
      t.string :state
      t.float :lat
      t.float :lng
      t.string :website
      t.integer :user_id
      t.timestamps
    end
  end

  def self.down
    drop_table :places
  end
end

You'll notice that each user has a place, so I updated the models to make that association and add some validation.
in user.rb

has_one :place

in place.rb

class Place < ActiveRecord::Base
  attr_accessible :state, :lat, :lng, :website, :user_id
  
  belongs_to :user
  
  validates_uniqueness_of :state, :user_id, : on => :create
  validates_presence_of :lat, :lng
end

I then added CRUD functionality for the places and added in some data. (If you are new to Rails, check out the getting started guide)

Next you want to output this data to a format that google maps can pick up, I used JSON.

  def index
    @places = Place.with_user_data

    respond_to do |format|
      format.html # index.html.haml
      format.json { render :json => @places }
    end
  end

If this is your first time using JSON I suggest getting the JSON viewer for firefox and reading How To Read JSON Using JQuery.

You’ll notice I used a named scope when creating the places object, this is so that I could explicitly select all the fields that needed to rendered to the JSON file.
in place.rb

named_scope :with_user_data, {
    :select => "places.*, users.first_name, users.last_name",
    :joins => :user
  }

At this point all of the data should be ready to view.

http://localhost:3000/places.json

**note that this image shows an example using jurisdictions instead of places and with additional data, but you’ll get the point **

To display the map I created a separate controller, set the layout to nil, and then accessed the map via Fancybox.

That said the actual view code is very bare

=content_for :head do
   %script{:src => "/javascripts/places_map.js "}
%body
      #map

And then the map javascript

var map;
	var arrMarkers = [];
	var arrInfoWindows = [];
	
	function mapInit(){
		var centerCoord = new google.maps.LatLng(38, -97); 
		var mapOptions = {
			zoom: 3,
			center: centerCoord,
			mapTypeId: google.maps.MapTypeId.TERRAIN
		};
		map = new google.maps.Map(document.getElementById("map"), mapOptions);
		
		$.getJSON("/places.json", {}, function(json){
			$.each(json, function(i,item){
				$("#markers").append('<li><a href="#" rel="' + i + '">' + item.place.name + '</a></li>');
				var marker = new google.maps.Marker({
					position: new google.maps.LatLng(item.place.lat, item.place.lng),
					map: map,
					title: item.place.state
				});
				arrMarkers[i] = marker;
				var infowindow = new google.maps.InfoWindow({
					content: "<h3>"+ item.place.state +"</h3><p>"+ item.place.first_name + "&nbsp;" +  item.place.last_name + ", &nbsp;" + "</p>",
					maxWidth: 100   
				});
				arrInfoWindows[i] = infowindow;
				google.maps.event.addListener(marker, 'click', function() {
					infowindow.open(map, marker);
				});
			});
		});
		    
	}
	$(function(){
		// initialize map (create markers, infowindows and list)
		mapInit();
		
		// "live" bind click event
		$("#markers a").live("click", function(){
			var i = $(this).attr("rel");
			arrInfoWindows[i].open(map, arrMarkers[i]);
		});
	});

And there you have it.

Let me know if you have any questions or comments.

Spree templating (rails3, spree.3)

18 Jan

I recently started a new project that included a spree store and I hadn’t done a spree implementation since they changed their contemplating logic. I had a really hard time finding comprehensive documentation on how to ‘skin’ the site to match that of my clients, so here are my notes.

The setup – Rails 3, Ruby 1.9.2, Spree .30.1

Getting Spree running

Spree’s getting started guide is really helpful is getting the initial store up and running.

I decided not to bring over all the test data instead just created an admin user and started from scratch.

rake db:admin:create

Through the admin (/admin) configuration tab, you can change the store name and  title .

When you look around your spree app file structure you’ll notice you don’t see any of the views and if you edit the application layout nothing happens. To add your theme you will have to create an extension and make your customizations there.

Create an extension for your theme
First change the spree gemfile to in your Gemfile to

gem 'spree', :git => "git://github.com/railsdog/spree.git", :tag => "v0.30.1"

and run bundle install

You can then create the extension

rails g spree:extension foo

A foo folder will now be in your project directory.

You can edit the application layout /foo/app/views/layouts/spree_application.html.erb

I did all my stylesheet editing outside of the extension – public/stylesheets (doesn’t seem like a best practice, but it didn’t work when i added css inside of the extensions public folder)

Hooks
Now lets say you want to add some code to one of the views, hooks is the best way to do this. Hooks basically provide a bookmark in the code that you can insert_before, insert_after, remove, or replace.

This is from an older version, but it was the best explanation of how to use hooks I could find: Spree hooks (v 0.11)

Add hooks in the following file /foo/lib/foo_hooks.rb

class FooHooks < Spree::ThemeSupport::HookListener

insert_before :homepage_products, :text => "HELLO!"

insert_after :product_description do
'<p><%= link_to("Back to products", products_path) %></p>'
end
end

Note – I noticed that you have to restart rails server for the hook changes to work.

To get a full list of hooks you can run grep -rh ‘hook :’ core/app/views | sed ‘s/^.*hook\s*//;s/[, ].*//’ | sort | uniq   or view this basic list of hooks from the spree guides.

If you can’t access the part of the file you need with hooks, you can override the core views.

Overriding Spree Core Files
By default files in your extension will override the core files.

For example I copied
/Users/me/.rvm/gems/ruby-1.9.2-p0/gems/spree_core-0.30.1/app/views/products/index.html.erb
to /foo/app/views/products/index.html.erb
and then made the needed changes.

Follow

Get every new post delivered to your Inbox.