ChangingThePresent
The Few, The Proud, The Pradipta 416
My Resume
Web DOC PDF
RTF ODT TXT
powered by emurse

resource_helper plugin

bryan / 13.Aug.2008

I am about to release resource_helper plugin. I wrote in while working on my client’s project and it has become invaluable to our team. It attempts to bridge the small gaps between ActiveRecord and ActiveResource and make them quack nearly the same. It also adds some convenience methods which I found myself rewriting for every new ActiveResource. I hope to release it by the end of the day today.

Hehe, my new acronym for god.

The config suggestion I posted earlier works in theory, but I was having some trouble getting it to work from init

What I ended up having to do was add

sleep
after some steps of the god init. Multiple sub-config loading from a main config file just wasn’t going to work. I’m am sure there is a better way, but this works for the time being, until I have more free time to work on Unrud itself.


# v.0.0.3
# cobbled by Bryan Taylor http://rubyisbeautiful.com
# god - Start/stop/check Unrud via init 
#
# chkconfig: - 85 15
# description: http://god.rubyforge.org/
# processname: god
# config: /etc/god.conf

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

[ -x /usr/bin/god ] || exit 0

RETVAL=0
prog="god" 

start() {
# Start daemon only
echo -n $"Starting $prog: " 
/usr/bin/god
sleep 5
  RETVAL=$?
  [ $RETVAL -eq 0 ] && {
     touch /var/lock/subsys/$prog
     success $"$prog" 
  }
  echo

#load the configs
if [ -e /u/apps/content/current/config/content.god ] ; then
  echo -n $"Loading content config: " 
  /usr/bin/god load /u/apps/content/current/config/content.god
  echo -n $"Loading admin config: " 
  /usr/bin/god load /u/apps/admin/current/config/admin.god
  sleep 5
  RETVAL=$?
  [ $RETVAL -eq 0 ] && {
     touch /var/lock/subsys/$prog
     success $"$prog" 
   }
   echo
else
  RETVAL=1
fi
return $RETVAL  
}

stop() {
    # Stop daemons.
    echo -n $"Shutting down $prog: " 
    /usr/bin/god quit &
        sleep 5
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
    return $RETVAL
}

reload() {
    echo -n "$reloading $prog config: " 
        /usr/bin/god load /u/apps/content/current/config/content.god
        /usr/bin/god load /u/apps/admin/current/config/admin.god
}

# See how we were called.
case "$1" in
    start)
      start
      ;;
    stop)
      stop
      ;;
        reload)
            reload
        ;;
    restart)
      stop
      start
      ;;
    status)
      /usr/bin/god status
      RETVAL=$?
      ;;
    *)
      echo "Usage: god {start|stop|reload|restart|status}" 
      exit 1
  ;;
esac      
exit $RETVAL

Also, I modified the init script a little, as god doesn’t quite behave like a typical *nix daemon.

Update:

via Twitter from Ivey: updates pushed to rubyforge.

I just checked and all is well; still, follow the advice below to get using git.

If you follow the merb core development, you’ll see that Ivey pushed 0.9.3 gems. Unfortunately it appears temporarily broken via the default install from rubyforge. For now, if you haven’t already hooked up to github and merb, now is the perfect time.


> git clone git://github.com/wycats/merb-core.git
> cd merb-core
> rake install
> cd ..
> git clone git://github.com/wycats/merb-more.git
> cd merb-more
> rake install

However poor the taste of the author in choosing a name, it is indeed a great way to monitor, nay, control pretty much anything.

I use god on my local dev box (mac) as well to keep all things developery running.

I got the init script from http://ezinearticles.com/?Why-Rails-Developers-Need-God&id=845672 and all the good info from http://god.rubyforge.org/

Handily, a god init script will of course start your mongrels et al when properly configured. Here is how I use a config template for the many gods-mongrels


host = `hostname`
app = "foo" 

case
when host =~ /theproductionbox/
  ports = %w{ 6400 6401 } 
  RAILS_ROOT = "/u/apps/#{app}/current" 
  shared_path = "/u/apps/#{app}/shared" 
  mongrel_cmd = "/usr/local/bin/ruby /usr/local/bin/mongrel_rails" 
  pid_dir = "#{shared_path}/pids" 
  log_file = "#{shared_path}/log/mongrel.log" 
  uid = 'production_guy'
  gid = uid
  ENV['RAILS_ENV'] ||= 'production'
  rails_env ||= ENV['RAILS_ENV']
  http_host = "fancy.productionbox.com" 
  http_path = "/" 
  http_code = "200" 
when host =~ /somedevbox/
  ports = %w{ 6400 } 
  RAILS_ROOT = "/u/apps/#{app}" 
  shared_path = "/u/apps/#{app}" 
  mongrel_cmd = "/usr/local/bin/ruby /usr/local/bin/mongrel_rails" 
  pid_dir = "#{shared_path}/tmp/pids" 
  log_file = "#{shared_path}/log/mongrel.log" 
  uid = 'development_guy'
  gid = uid
  ENV['RAILS_ENV'] ||= 'development'
  rails_env ||= ENV['RAILS_ENV']
  http_host = "ratbike.devbox.com" 
  http_path = "/" 
  http_code = "200" 
end

ports.each do |port|
  God.watch do |w|
    w.group = app
    w.uid = uid
    w.gid = gid
    w.name = "#{app}-mongrel-#{port}" 
    w.interval = 30.seconds
    w.start = "#{mongrel_cmd} start -d -a 0.0.0.0 -p #{port} -P #{pid_dir}/dispatch.#{port}.pid -e #{rails_env} -c #{RAILS_ROOT} -l #{log_file}" 
    w.stop = "#{mongrel_cmd} stop -P #{pid_dir}/dispatch.#{port}.pid" 
    w.start_grace = 30.seconds
    w.restart_grace = 30.seconds
    w.pid_file = File.join(pid_dir, "dispatch.#{port}.pid")

    w.behavior(:clean_pid_file)

    w.transition(:init, { true => :up, false => :start }) do |on|
      on.condition(:process_running) do |c|
        c.running = true
      end
    end

    w.transition([:start, :restart], :up) do |on|
      on.condition(:process_running) do |c|
        c.running = true
      end
      on.condition(:tries) do |c|
        c.times = 5
        c.transition = :start
      end
    end

    w.transition(:up, :start) do |on|
      on.condition(:process_exits)
    end  

    w.transition(:up, :restart) do |on|
      on.condition(:memory_usage) do |c|
        c.interval = 60.seconds
        c.above = 57.megabytes
        c.times = [4, 5]
      end
      on.condition(:cpu_usage) do |c|
        c.interval = 60.seconds
        c.above = 10.percent
        c.times = [3, 5]
      end
      on.condition(:http_response_code) do |c|
        c.host = http_host
        c.path = http_path
        c.code_is_not = http_code
        c.timeout = 30.seconds
    c.interval = 30.minutes
      end
    end

    # lifecycle
    w.lifecycle do |on|
      on.condition(:flapping) do |c|
        c.to_state = [:start, :restart]
        c.times = 5
        c.within = 5.minute
        c.transition = :unmonitored
        c.retry_in = 10.minutes
        c.retry_times = 5
        c.retry_within = 2.hours
      end
    end
  end
end

God::Contacts::Email.message_settings = {
  :from => 'god@rubyisbeautiful.com'
}

God::Contacts::Email.server_settings = {
  #settings
}

God.contact(:email) do |c|
  c.name = 'bryan'
  c.email = 'bryan@rubyisbeautiful.com'
end
		
		
	

making errors better

bryan / 24.Apr.2008

First, I haven’t written in awhile. Like many bloggers that I follow, success in one area diminishes my capacity in other areas. My contracting business is doing very well. More than that however, I don’t like to waste space or mince words on my blog, as you have already noticed. I won’t write unless I have something that I think is worth sharing; I won’t write just to keep a fresh article in the feeds.

I have been doing a lot of debugging – mostly of the needle-in-a-haystack variety. Simultaneously I am working on a new, re-engineered version of the legacy app I am debugging. So I have the opportunity to do some things “right” this time (I didn’t write the legacy app, and the developer who did is AWESOME and a friend. I am not criticizing the code here. What always happens is the problems and business rules become clearer as the project matures, giving rise to an opportunity to craft a better model)

There are of course great plugins to do some of this, and more. I personally have found that in some cases less is more and projects that rely to heavily on 3rd party code may end up paying for at debug time.

Here are some tweaks to errors and whatnot that I use:

1. extend StandardError with a simple to_xml method, for use in ActiveResource and pretty much anywhere:

class StandardError
  def to_xml
    return <<-ENDOFDOC
      <error type='#{self.class.to_s}'>
        <message>#{message}</message>
      </error>
    ENDOFDOC
  end
end
1.5. UPDATE: I also added a status method, since I use resources so heavily.

@status=400 #its never the server's fault
attr_accessor :status
and in the custom errors mentioned below, change as needed:

LocalApplication::SomeParameterIsMissing.new.status # => 406

This works nicely for StandardError and any descendent classes that don’t already have a to_xml method. For ActiveRecord:: and some other error classes, there is a to_xml which will override this one.

2. put a general error handler in ApplicationController


def handle_error(err=nil)
  begin
    if err.nil?
      @error = GenericNilError.new("Oops, something happened...")
    else
      @error = err
    end
    respond_to do |flavah|
      flavah.xml { render :xml => @error.to_xml, status => 500 and return false }
      flavah.html  # a template for error
    end
  rescue StandardError => e
    # some failsafe that hits a static
    render :nothing => true, :status => 500 and return false
  end
end
3. use local errors As in the example above, roll your own errors. Then you respond in customized ways. If you’re not already rescuing different kinds of errors and handling them in unique ways, you may want to explore that.

module LocalApplicationError
  class GenericError < StandardError ; end
  class ShouldNeverHappenError < StandardError ; end
  # etc...
end
4. have an error log So much better than scrolling through #{RAILS_ENV}.log

err_logger = Logger.new #customize how you want it
[ActiveRecord ActiveResource ActionController].each do |mod|
  mod.module_eval <<- ENDOFMONKEY
    include LocalApplicationError #why not throw this in there too, see #3 above
    @err_logger = err_logger
    mattr_reader :err_logger
  ENDOFMONKEY
end

5. Use specs so you don’t raise unknown errors!

new sites for merb docs

bryan / 31.Mar.2008

I recently created merbdoc.com (a.k.a. merbapi) to help the Merb community out. Let me know how if its useful, or how I can improve it. Its brand new, so it might be down for the next day or so.

Here’s a very easy way to change the default render format. Its not necessarily the best way for you. Consider that rendering HTML is hardcoded in the code and it is probably default in the browser/client’s Accept header.

rails/action_pack/lib/action_view/base.rb


when parameter_format.blank? && accept_format != :js
          @template_format = :html

For my usage, the best way to change was to add a method to application.rb and call it as a before filter (either by default in application.rb or as needed in each controller) (updated to a better way)


protected
def set_request_header
    xml_string = 'application/xml'
    request.instance_eval("@accepts=Mime::Type.lookup('#{xml_string}')")
    request.headers['HTTP_ACCEPT']  = xml_string
    request.env['HTTP_ACCEPT']      = xml_string
end

it’s not really “playing nice” but it works and is easy to debug and undo

and now for a break

bryan / 21.Mar.2008

Its Spring Break, which means nothing to me other than that my kids are home from school. Work is difficult. This week instead of carelessly crafter semi-digested thoughts on Ruby et al., I bring you a picture from railsblog

quick tip: bash profile

bryan / 13.Mar.2008

If you use a Unix-like development environment, this may be helpful. Here's some snippets from my .bash_profile on Leopard.


function wo {
  cd "/Users/bryan/apps/$1";
}
function devcon {
 eval script/console $1;
}
function testcon {
 eval "script/console test $1";
}
function prodcon {
 eval "script/console production -s $1";
}
function prodcon_live {
 eval "script/console production $1";
}

So I get something to go to a certain project I'm working on and use the console quickly.


bash:~> wo merb-core
bash:/Users/bryan/apps/lazy_developer> devcon
>>

It saves a lot of typing.

merb on github and merb filters

bryan / 04.Mar.2008

Well after joining Github recently to work on Merb I did a few things: submitted my first patch, got rejected, and learned a lot about git and merb. xD

Wycats from merb kindly pointed out that the “bug” I had discovered was actually a feature! Indeed it is. Let’s have a look.

(original Lighthouse ticket)

working_foo.rb


class WorkingFoo < Application
  def index
    redirect 'http://merbivore.com'
  end
end

failing_foo.rb


class FailingFoo < Application
  before :choke

  def choke
    redirect 'http://merbivore.com'
  end
end

So what happens? In retrospect my thoughts were clearly biased by Rails. This application would work in Rails. But that doesn’t mean it is necessarily a smart way to do things. In failing_foo.rb the application is kind of losing control; the filter redirects and the session is abruptly interrupted. The outcome is the same in that the user agent is eventually redirected where they need to go, but it’s not the best way of doing it.

Here is the Merb way

merby_foo.rb


class MerbyFoo < Application
  before :awesomeness

  def awesomeness
    throw :halt, redirect "http://merbivore.com" 
  end
end

I read about 75% of the Merb code over the weekend to write a patch, and what I came up with was almost the same as the above MerbyFoo (suggested by Wycats), but with a subtle difference. I placed my throw :halt in the redirect method of the Controller mixin with a check to see if it was being called in a filter. Tsk on me. Wycats and the merb way is better, and now I understand it. You would normally expect the before filter that calls redirect to “halt” the before filters, but perhaps not always.

Merbs filters (in abstract_controller.rb) are flexible. The throw mechanism in filters allows passing a String, Proc, Symbol or nothing. Perhaps the redirect involves something complex:

before :check_em

def check_em
  throw :halt, :complex_stuff
end

def complex_stuff
 redirect "http://google.com" if user =~ /googler/
 redirect "http://yahoo.com" if user =~ /yahooligan/
end

merb upgrade part 2

bryan / 29.Feb.2008

I built the gem on my local machine like this:


git clone git://github.com/wycats/merb-core.git
git clone git://github.com/wycats/merb-more.git
cd merb-core
rake install
cd ../merb-more
rake install
gem list --local merb

*** LOCAL GEMS ***

merb (0.9.0)
merb-action-args (0.9.0)
merb-assets (0.9.0)
merb-builder (0.9.0)
merb-core (0.9.0)
merb-gen (0.9.0)
merb-haml (0.9.0)
merb-mailer (0.9.0)
merb-more (0.9.0)
merb-parts (0.9.0)
merb-test (0.9.0)


excellent

git on the road to merb

bryan / 29.Feb.2008

I decided to upgrade my installation of merb from the older merb-0.5.x to the new "merb-next" which is re-numbered 0.9.x and available on github.

I knew something was going to finally push me to getting and learning git; so there it is. First thing is to dl and compile of course.
As I found out after a halt in the compile, Leopard needs a SYS V type utility called msgfmt. After a lot of googling and messing around, I found this article by Sean Santry which I found to be most helpful.

I truly was going to install the GNU gettext utilities as well, but I was unable to compile them easily as well. Since I was already 3 or 4 tangents removed from upgrading merb, I decided to use Sean's workaround.
NO_MSGFMT=yes make prefix=/usr/local all

open safari page in firefox

bryan / 24.Feb.2008

I was going to write something in Applescript (after learning Applescript) to open a Safari page in Firefox. I found a somewhat dated example here which I updated slightly, and it works for me YMMV.


tell application "Safari"
	activate
	set my_URL to the URL in document 1
end tell
-- Convert Unicode Text of my_URL to Plain text
set my_URL to «class ktxt» of ((my_URL as string) as record)

tell application "Firefox"
	activate
	Get URL my_URL
end tell

quit

new plugin: lazy_developer

bryan / 23.Feb.2008

I wrote this to facilitate doing things faster in the console. Pretty mindless, but fun to get involved more at rubyforge.
install like your usual plugin (I recommend piston)


svn checkout http://lazy-developer.rubyforge.org/svn/
or
svn checkout svn://rubyforge.org/var/svn/lazy-developer

and you get:


Foo.ff          find the first foo
Foo.fl          find the last foo
Foo.fa         find all foos
Foo.f1(arg)  find a foo with this condition
Foo.f(arg)    find all foos with this condition

let me know how it goes for you

micro-tabbed theme bugfix

bryan / 22.Feb.2008

I saw no visible means of contacting the authors of the micro-tabbed theme, and their svn was down. I consider this to be a pretty crappy bug: they hardcoded their own url into the liquid so links generated map to them. Unintentional or otherwise, its pretty bad. I checked around some other site that use this theme, and they have the same issue. To fix, edit _entry.liquid and replace the default with this:

http://{{ site.host }}{{ article.url }}

back to top

micro theme by seaofclouds, and powered with Mephisto Hosting by hostingrails.com