Archive for the ‘Rails’ Category

Freezing gems with Gem.use_path

Wednesday, April 9th, 2008

Edge rails now has gem dependency support built in, with tasks to freeze in vendor/gems.

I have tried a bunch of different methods, and things like setting $GEM_HOME or using gemsonrails work well. But lately I have been using the Gem.use_paths method.

If you put this in the config/environments rb:

Gem.use_paths(nil, [ "#{RAILS_ROOT}/vendor/rubygems" ])
# Gem.path is now:
# ["/Users/ghandford/Projects/my_rails_proj/vendor/rubygems", "/Library/Ruby/Gems/1.8"]

The vendor/rubygems directory is the same structure as system gems folder:

  vendor/rubygems/cache
  vendor/rubygems/doc
  vendor/rubygems/gems
  vendor/rubygems/specifications

The convention I use is any non-native gems get frozen with the project, and then all the native gems go in the system gem path, which gets you pretty close to clone/checkout and rake setup.

As far as unpacking and install gems, you just use gem install with GEM_HOME of your local project:

GEM_HOME=`pwd`/vendor/rubygems gem install capitate

A benefit of the use_paths method is that you can create scripts in your Rails project that use gems frozen in your project (and not necessarily have to require rails or environment.rb to get at them).

./script/my_non_rails_script
  require 'rubygems'
  Gem.use_paths(nil, [ File.dirname(__FILE__) + "/../vendor/rubygems" ])

Has anyone else tried this before?

politweets

Thursday, January 10th, 2008

We built another twitter app, this time tracking candidates names. Its called politweets.

One #1 referrer today was from 100shiki. I’ve always been big in Japan.

Hopefully this one is a little more relevant than tracking curse words. But I still think the bitch balls‘er is awesome.

nginx conf with alternate cache dir

Monday, January 7th, 2008

Its a good idea to use an alternate cache directory in rails (in your environment.rb):

config.action_controller.page_cache_directory = RAILS_ROOT + "/public/cache/"

This makes it easier to sweep. To setup nginx to pick up from a rails alternate cache directory like public/cache, I used:

if ($http_user_agent ~* "(iPhone|iPod)") {
  rewrite ^/$ /iphone break;
  proxy_pass http://mongrel-pt;
  break;
}
 
if (-f $request_filename) {
  break;
}
 
if (-f $document_root/cache/$uri/index.html) {
  rewrite (.*) /cache/$1/index.html break;
}
 
if (-f $document_root/cache/$uri.html) {
  rewrite (.*) /cache/$1.html break;
}
 
if (-f $document_root/cache/$uri) {
  rewrite (.*) /cache/$1 break;
}
 
if (!-f $request_filename) {
  proxy_pass http://mongrel-pt;
  break;
}

It was a little tricky to figure out to use the $uri variable. The first rewrite is used for iphone requests so it doesn’t get the non-iphone cached page.

twittertale.com

Monday, December 17th, 2007

Some friends and I did a twitter thing where we catch tweets with curse words and put them on twittertale.com. Its kind of funny. The backend twitter side is xmpp4r and xmpp4r-simple straight up ruby. And the web side is fresh rails 2.0 happiness.

On a side note, if you are doing ruby sans rails with mysql gem, you need to take care of the character encoding on the connection, which you can do by sending SET NAMES UTF8; after connect or I guess by setting the default on connection settings in my.cnf

View paths in Rails 2.0

Monday, December 17th, 2007

New in rails 2.0:

ActionController::Base.append_view_path

This is useful for loading views from a plugin or gem:

ActionController::Base.append_view_path(File.dirname(__FILE__) + "/views")

There is also ActionController::Base.prepend_path.

set_trace_func and filter on regex

Wednesday, August 29th, 2007

I needed to use the trace_func to figure out a bug, and I came up with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  class Tracer
    
    class << self
      
      def on(io = STDERR, regex = nil)
        set_trace_func proc { |event, file, line, id, binding, classname|
          if !regex.blank?
            s = format("%8s %s:%-2d %10s %8s\n", event, file, line, id, classname)
            io.printf(s) if s =~ regex            
          else
            io.printf("%8s %s:%-2d %10s %8s\n", event, file, line, id, classname)
          end
        }
      end
    
      def off
        set_trace_func nil
      end
    
      def trace(io = STDERR, regex = nil, &block)
        on(io, regex)
        retval = yield if block_given?
        off      
        retval
      end
      
    end
  end
  
end

Then Tracer.trace { 1 + 1 } or specify a regex filter:

1
2
3
4
5
>> Tracer.trace(STDERR, /Fixnum/) { 1 + 1 }
  c-call (irb):2           +   Fixnum
c-return (irb):2           +   Fixnum
=> 2
>> 

GC and ObjectSpace

Friday, August 24th, 2007

I saw this at the Rails Edge conference and thought it was cool; aside from its really expensive to implement in JRuby.

1
2
3
4
5
6
7
8
9
10
>> GC.disable
=> false
>> instances = 0
=> 0
>>  ObjectSpace.each_object(Artist) { |a| instances += 1 }
=> 0
>> Artist.find(:all, :limit => 5)
=> [#<Artist:0x327d348 @attributes={....
>>  ObjectSpace.each_object(Artist) { |a| instances += 1 }
=> 5

Markup, CSS and Helper cataloging (Part deux)

Monday, June 25th, 2007

I should be using ERB instead of eval. But because you can’t use <% inside a string block in your view (that I can figure out; <<EOF didn’t seem to be working in a template). And if you don’t want to specify the code string in your controller you can use [% ... %]. Here is the source I am using for our code helper now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  def erb_code(code) 
    ERB.new(code).result(binding)    
  end
  
  def render_code(code, options = {}) 
    %{ <pre class="helper">\n<code class="ruby">\n#{h(code)}\n</code>\n</pre> }
  end
  
  def render_markup(html)
    doc = REXML::Document.new(html)
    markup = ""
    doc.write(markup, 2)
    
    %{ <pre class="markup">\n<code class="html">\n#{h(markup)}\n</code>\n</pre>\n }    
  end
  
  def render_eval(html)
    %{ <div class="eval">#{html}</div> }
  end
    
  def code_helper(code)
    code.gsub!(/\[%/, "<%").gsub!(/%\]/, "%>")    
    html = erb_code(code)
    render_code(code) + render_markup(html) + render_eval(html)
  end

Then you can do things like:


  <%= code_helper %{ [%= rating_field(:rating, :effectiveness) %] } %>

and you could also dump it in a helper:

1
2
3
4
5
6
7
8
9
def code_rating_form_field 
  <<-EOF
   <% form_for :rating, @rating2 do |f| %>
     <%= f.rating_field(:effectiveness) %>
   <% end %>
  EOF
end

  // And in your view: <%= code_helper(code_rating_form_field) %>

Markup, CSS and Helper cataloging

Monday, June 18th, 2007

At work, we have a catalog of markup and CSS and any ruby helpers. I wrote this helper for it which takes a code string and spits it out, evals it, and provides the eval’ed html wrapped and indented. The code-highligher does all the highlighting.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def code_helper(code) 
   help_block = %{ <pre class="helper">\n<code class="ruby">\n<%= #{h(code)} %>\n</code>\n</pre> }
    
    result = instance_eval code, "generated code (#{__FILE__}:#{__LINE__})"
    result_block = %{ <div class="eval">#{result}</div> }
    
    doc = REXML::Document.new(result)
    markup = ""
    doc.write(markup, 2)
    
    markup_block = %{ <pre class="markup">\n<code class="html">\n#{h(markup)}\n</code>\n</pre>\n }
    
    %{ #{help_block} #{markup_block} #{result_block} }
end

And usage:


<%= code_helper %{ will_paginate(@count, @per_page, @page_num, { :extra_param => "extra1" }) } %>

would display the code, the (escaped) markup that it generates, and then the straight up html.

Render content in layout

Wednesday, May 30th, 2007

I came up with a hack to render content inside a layout, from the controller:

1
2
3
4
5
6
7
8
9
10
  def content_with_layout(content_for_layout, controller, layout = "the_layout")
    locals = { :params => controller.params }
    template = controller.class.view_class.new(controller.class.view_root, locals, controller)
    template.instance_variable_set("@content_for_layout", content_for_layout)    
    
    # This might work to get assigns? untested...
    #template.assigns = controller.template.instance_variable_get("@assigns") 

    template.render_file("layouts/#{layout}", true)    
  end  

You have to pass in any locals you want, and if you want the use assigns in your layout you would have to set the template.assigns. There was some plugin to give you extra layouts in the view but I forget what it was called. Anybody know where that is?

Update: The inside layout is at: http://fora.pragprog.com/rails-recipes/write-your-own/post/144