The Hacker said over 5 years ago permalink Comment? (0)
Tagged: ruby rails gem geocoding google

Google-Geocode Gem Woe's

While using the very cool google-geocode gem for ruby, I ran into a small (read: big) problem.

Do a search for “Trinidad” by itself and you get something like:

Communication error: #<REXML::ParseException: Missing end tag for 'AdministrativeAreaName' (got "AdministrativeArea")

The problem lies not in the gem but in ruby’s REXML and how it deals with the xml google sends back. This only happens when international characters are involved.

After doing a little googling I saw a patch for rexml which I changed into a monkey patch for google-geocodes helper library rc-rest.

This monkey patch will solve all your accent mark woe’s.

class RCRest
  
  def get(method, params = {})
    url = make_url method, params

    url.open do |xml|
      body = xml.read

      res = REXML::Document.new Iconv.conv("UTF-8//Ignore", 'UTF-8', body)
  
      check_error res

      return parse_response(res)
    end
  rescue IOError, SystemCallError, SocketError, Timeout::Error,
         REXML::ParseException => e
    raise CommunicationError.new(e)
  rescue OpenURI::HTTPError => e
    begin
      xml = REXML::Document.new e.io.read
      check_error xml
    rescue REXML::ParseException => e
    end
    new_e = CommunicationError.new e
    new_e.message << "\n\nunhandled error:\n#{xml.to_s}"
    raise new_e
  end
  
end

The magical change is the inclusion of Iconv to make REXML happy.

The Hacker said over 5 years ago permalink Comment? (0)
Tagged: syntax highlighting javascript ruby perl rails

Syntax Highlighting for Everyone!

I recently integrated a javascript based syntax highlighter into this blog. Its very easy to do and quiet useful. Here is a quick rundown. I also go over some alternative methods afterwards.

The software I ended up using was SyntaxHighlighter

Instructions can be found here just include some files, run the javascript and your gold.

Once thats in place all you have todo is invoke:

<pre name="code" class="yourlanguage">
   awesome code snippit here

Where ‘yourlanguage’ is one of ruby,perl,etc

There is a very useful option which allows you to match line numbers to the file you may be refering to (for example your code may begin on line 10).

<pre name="code" class="yourlanguage:firstline[10]">
   awesome code snippit here

Here is an example from line 35 from a rails controller (Note the line numbers on the left)

def show
  @owner = User.find(params[:user]) || User.find(1)
  @blogs = Blog.paginate :conditions => ["(user_id = ?) AND NOT disabled", @owner.id], 
    :order => 'updated_at DESC', :per_page => 5, :page => params[:page]
end

SyntaxHighlighter supports out of the box:

  • Csharp
  • C++
  • CSS
  • Delphi
  • JavaScript
  • Java
  • Php
  • Python
  • Ruby
  • SQL
  • VisualBasic
  • XML (Which works well for xhtml files)

In addition you can grab shBrushPerl.js which adds perl support.

And thats all there is to it! Syntax Highlighting with Client Side Javascript.

I would also like to point out some other ways to convert code into markup.

  • Coderay integrates well with ruby on rails.
  • GeSHi is a PHP based generator.
  • Highlight is a command line (and gtk gui) based app.

At the very least Highlight’s console output can be grabbed and fed into your web application no matter what language. It also has a cool 256 Color Xterm output which is great for piping code into from grep or less.

Highlight also comes with a slew of existing color schemes in CSS which is nice.

There are many more highlighters out there, google is your friend.

Enjoy the shiny colors!

The Decider said over 5 years ago permalink Comment? (0)
Tagged: search rails haml ruby

Easy Whole Site Searching

This is a method of searching all or some of your tables using Ruby on Rails and MySQL’s ability to do Full Text Searches. This method is all ruby without using ferret or sphinx ,both of which are very good tools.

This whole idea can probably be put into a plugin but I don’t have the time to mess with that yet.

First the model:

class Search < ActiveRecord::Base
  belongs_to :account
  belongs_to :searchable, :polymorphic => true 

  # this blindly creates an index for a particular klass / account combination.
  # there must be an account_id field in the klass being searched
  #
  # Note: This searches all columns of all records for this account which
  # is probably Too Much Information, TMI, Baby. You may want to define a
  # method called column_names_to_search which will restrict what is searched.
  #
  # Note: You may want to overide this method by defining your own
  # 'create_searchable_index' in your class.
  def self.create_searchable_index(account, klass)
    raise unless account.kind_of?(Account)
    return klass.create_searchable_index(account) if klass.respond_to?('create_searchable_index')
    Search.delete_all ["account_id = ? and searchable_type = ?", account[:id], klass.to_s]
    klass.find(:all, :conditions => "account_id = #{account[:id]}").each do |thing|
      if klass.respond_to?('column_names_to_search')
        text = klass.column_names_to_search.map{|col| thing.send(col).to_s}
      else
        text = klass.column_names.map{|col| thing.send(col).to_s}
      end
      Search.create! :account_id => account[:id], :searchable_id => thing.id, :searchable_type => thing.class.to_s, :searchable_text => text.join(' ')
    end
    Search.count :conditions => "account_id = #{account[:id]} and searchable_type = '#{klass}'"
  end

  def self.match(account, query, just_this_object = nil)
    matches = []
    sql = %{SELECT searchable_id, searchable_type FROM searches WHERE account_id = #{account.id} AND MATCH searchable_text AGAINST ('#{query}')}
    if just_this_object
      sql += %{ AND searchable_type = '#{just_this_object}'}
    end

    Search.find_by_sql(sql).each do |found|
      matches << eval("#{found.searchable_type}").find(found.searchable_id)
    end
    matches
  end
end

As the comments suggest you will probably be better off writing a method in the models you want to search. This allows you to expand certain associations or delete sensitive data. Here’s an example where I’m removing the id, updated_at, system, and account_id from the stuff I search, self.column_name_to_search. self.create_searchable_index does the heavy lifting of:

  1. Deleting the old index
  2. Finding all the groups for this account and looping on them to
    1. get just the columns I want
    2. add the user’s name to the searchable text so when we search for “Chad” we get the user and all the groups that use is in.
    3. create the entry in the Searches table.
  3. Return the count of how many entries were created.
class Group < ActiveRecord::Base
  belongs_to :account
  has_many   :group_user_memberships, :order => 'position', :dependent=> :destroy
  has_many   :users, :through => :group_user_memberships, :order => "group_user_memberships.position, last_name, first_name, username"

# ... 

  private

  def self.column_names_to_search
      self.column_names - ["id", "updated_at", "system", "account_id"]
  end

  def self.create_searchable_index(account)
    Search.delete_all "account_id = #{account[:id]} and searchable_type = 'Group'"
    Group.find(:all, :conditions => ["account_id = ?",account[:id]], :order => 'name').each do |group|
      text = Group.column_names_to_search.map{|col| group.send(col).to_s}
      text << group.users.map(&:name)
      Search.create! :account_id => account[:id], :searchable_id => group[:id], :searchable_type => Group.to_s, :searchable_text => text.flatten.join(' ')
    end
    Search.count :conditions => "account_id = #{account[:id]} and searchable_type = 'Group'"
  end

end

The controller is very simple. It takes the form input which is displayed on everypage ala the layout. We use haml for markup.

-form_tag(:controller => 'search', :action => 'index' ) do
  %input.search_button{ :name => 'search_text', :type => 'text', :size=> '20', :value => (session[:search_text] || 'Search'), :onclick => 'this.focus();this.select()', :onfocus => 'this.select()' }/
  = submit_tag 'Search'

And finally the controller. There are 2 methods. One builds the indexes and the other does the match.

require 'benchmark'

class SearchController < ApplicationController
  layout 'home'
  before_filter :only_admin, :except => [:index]

  def index
    session[:search_text] = params[:search_text]
    @bench = Benchmark.measure do
      @matches = Search.match @user.account, session[:search_text] 
    end
  end

  def create_index
    count = 0
    SEARCH_CLASSES.each do |klass|
      count += Search.create_searchable_index(@account,klass)
    end
    flash[:success] = "Indexed #{count} records"
    redirect_to :controller => 'home', :action => 'index'
  end

  private

  def only_admin
    permit SUPERUSER_GROUP_NAME
  end
end

The view for the search results is pretty simple. Rather than create a unified view for all models that can be searched I create a partial called _search.haml in the views for their corresponding controller. You don’t have to do this but probably you will want to differentiate your models display results.

#search
  %br/
  %h3
    Found 
    = @matches.nitems
    matches for
    %span.italic
      = '"' + session[:search_text] + '"'
    in
    = sprintf "%2.3f", @bench.real
    seconds
  %br/
  
  %ul
    - @matches.each do |thing|
      %li.no_list_style
        %strong
          = thing.class.to_s
        %br/
        = render(:partial => %{#{thing.class.to_s.tableize}/search}, :locals => {:thing => thing}) #rescue thing.inspect
      %br/

The Decider said over 5 years ago permalink Comment? (0)
Tagged: conference ruby rails

acts_as_conference

We are all signed up! See you in Orlando.



The Hacker said over 5 years ago permalink Comment? (0)
Tagged: ruby rails functional testing

A Window Into Functional Tests

So like any ruby blooded human, I create functional tests for my rails applications. However, things don’t always go as planned; a redirect instead of a success, but where to?, the assigns is right, but the flash was wrong, etc.

Sometimes you just need a way to peek at what you get back. If you enjoy gouging your eyes out you can do a puts @response or @response.body

A slightly better alternative is to spit the body to a file and preview it in firefox.

    tmpfile = File.new(tmpname = 'tmp/test_page.html', "w")
    tmpfile.puts @response.body
    tmpfile.close
    `firefox #{tmpname}`

Put this after any get, post, etc, and you will get a decent html output of your view (sans stylesheets and valid links) Although nothing is stopping you from outputting to public, running script/server, and viewing it from there.

  • If your dealing with redirects, don’t forget about follow_redirect!
  • If your crossing controllers, use integration tests =)

It’s not the be all end all of solutions, but it helps for a quick glimpse while fixing tests.
Hope it helps!

The Hacker said over 4 years ago permalink Comment? (0)
Tagged: rails javascript ruby sugar

Flexible date input and manipulation in javascript with date.js

date.js is a great little JavaScript library that can make your life a lot easier.

If your used to ruby’s date functions then date.js will make you feel right at home.

date.js can:

  • Parse strings into dates.
  • Add and Subtract time in days,hours,months or years.
  • Easily return “x” “day of week” of “month”
  • Boolean assertions for day, week, month, year.
  • Turn you into a JavaScript ninja.

Note: Some of the syntactic goodies require ‘sugar.js’

Going into the future is no problem for date.js

Date.today().add(5).days(); Date.today().next().friday();

Interested in this Friday? April of this year?

Date.friday(); Date.april();

What about the first friday of april? No Sweat!

Date.april().first().friday();

Assert any date properties you want.

Date.today().is().friday(); // returns true orfalse

It can parse just about anything you throw at it.

Date.parse(‘today’); Date.parse(‘tomorrow’); Date.parse(‘July 8’); Date.parse(‘July 8th, 2007’); Date.parse(‘July 8th, 2007, 10:30 PM’); // Even crazy! things like Date.parse(‘last april’); Date.parse(‘+2days’);

There are also some fun number functions.

(8).days().fromNow(); (2).months().ago();

For more reading, checkout: date.js examples

The Decider said over 4 years ago permalink Comment? (0)
Tagged: rails mongrel ruby nginx

Protect Staging Server with Password

When developing a new application and releasing often you may want to protect the site from prying eyes. A simple way to do this when using the nginx web server is to use basic http authentication.

I prefer to do this in the nginx config file so it doesn’t impact local development.

You’ll need to create a password file using htpasswd command line utility. This file should be relative to the install directory of nginx. The default install would place this file in /usr/local/nginx

sudo htpasswd -cb /usr/local/this_hosts_password_file username password

Next, you need to tell nginx to use basic auth for any access to this (virtual) host. I place the 2 relevant lines in the server portion of the config file

server { listen 80;

  1. auth_basic “Login to see this alpha site.”;
    auth_basic_user_file this_hosts_password_file;

  2. }

A login will now be presented for any entry into the site.

The Decider said over 4 years ago permalink Comment? (0)
Tagged: ruby rails bdoc hanna

Pretty Local Rdoc

From the RubyInside site a couple of gems to make your local rdocs look and behave nicer.

activerecord-2.3.2 - Bdoc_1239019365281

To reap the benefits:

sudo gem install mislav-hanna sudo gem install manalang-bdoc sudo hanna —gems bdoc

The Decider said over 3 years ago permalink Comment? (0)
Tagged: ruby logic

De Morgan, Ruby

#De Morgan the Ruby way

[true,false].each do |p|
  [true,false].each do |q|
    puts "p=#{p} q=#{q}"
    if !(p or q) == (!p and !q)
      puts "De Morgan Rules! !(p or q) == (!p and !q)"
    else
      puts "De Morgan is a Liar!"
    end

    # if find yourself writing
    if !p and !q
      print "-"
      # you could be writing 
      unless p or q
        puts "if !p and !q equivalent to unless p or q"
      end
    end


    if !(p and q) == (!p or !q)
      puts "De Morgan Rules! !(p and q) == (!p or !q)"
    else
      puts "De Morgan is a Liar!"
    end

    # if find yourself writing
    if !p or !q
      print "-"
      # you could be writing 
      unless p and q
        puts "if !p or !q equivalent to unless p and q"
      end
    end

  end
end

The Decider said over 2 years ago permalink Comment? (0)
Tagged: ruby

EOY Ruby Roundup

I don’t know how I missed this EOY Ruby Roundup

Good stuff.

The Decider said over 2 years ago permalink Comment? (0)
Tagged: ruby

read this post unless busy

I really like unless but only if it makes something much more readable. Of course Jamis beat me to it