Posts about rails

Turbogears and ReML

I followed the Turbogears 20 minute tutorial here. The first impressions of Turbogears are:
  1. It's a bit more verbose than rails: there's more plumbing - you have to explicitly define which view you want to use for each action, as supposed to doing everything based on convention.
  2. you explicitly pass the local variables to the view as a hash, as supposed to using class or global variables
  3. Turbogears uses a template engine called kid by default, which is very different from rails' erb in philosophy, there's more emphesis on designer friendliness and higher level support for template inheritence
  4. Python/Turbogears in general is safer than ruby/rails - see my last post, in that you usually get more informative errors, such as NameError: global name 'pag' is not defined rather than nil when you didn't expect it
  5. The development feedback is not quite as good as rails. Turbogears requires a restart everytime you make a change. The restart is automatically triggered everytime you save a file in the project, and it is very fast, but it still takes about 5 seconds to rails' 0(ruby has this luxury because of its open classes)
I am hip to Haml so I had to see if I could get it working with Turbogears. I found a couple of implementations: ReML and GHRML. Tried them both, ReML was simpler and more approachable, so I wrote a Turbogears plugin for it. The important bit of the plugin code is here:

from reml import TemplateLoader

class RemlTg(object):
 
  def __init__(self, extra_vars_func=None, options=None):
    pass

  def load_template(self, templatename):
    "Find a template specified in python 'dot' notation."
    parts = templatename.split('.')
    return TemplateLoader('/'.join(parts[0:len(parts)-1])).load(parts[len(parts)-1] + '.reml')

  def render(self, info, format="html", fragment=False, template=None):
    "Renders the template to a string using the provided info."
    return self.load_template(template).render(info)


After that, I converted the views in the tutorial into ReML. Let me do a wc on them for comparison, wait just a minute...

$ wc wiki20/templates/*.kid
  25   76 1068 wiki20/templates/edit.kid
  71  173 2802 wiki20/templates/master.kid
  21   56  773 wiki20/templates/page.kid
  21   50  705 wiki20/templates/pagelist.kid
 138  355 5348 total
airport@wedding-singer ~/documents/play/turbogears/Wiki-20
$ wc wiki20/templates/*.reml
  16   41  492 wiki20/templates/edit.reml
  38   86 1338 wiki20/templates/master.reml
  12   30  327 wiki20/templates/page.reml
   8   24  190 wiki20/templates/pagelist.reml
  74  181 2347 total


So that's about a 50% code reduction, not bad. Here's a Sample for comparison:

page.kid:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://purl.org/kid/ns#"
      py:extends="'master.kid'">
<head>
<title> ${page.pagename} - 20 Minute Wiki </title>
</head>
<body>
    <div class="main_content">
        <div style="float:right; width: 10em">
            Viewing <span py:replace="page.pagename">Page Name Goes Here</span>
            <br/>
            You can return to the <a href="/">FrontPage</a>.
        </div>

        <div py:replace="XML(data)">Page text goes here.</div>
        <p><a href="${tg.url('/edit', pagename=page.pagename)}">Edit this page</a></p>

    </div>
</body>
</html>


page.reml
- append('master.reml')
- def title():
  =page.pagename
- def content():
  %div: 'style':'float:right; width: 10em'
    Viewing
    %span=page.pagename
    You can return to the
    %a: 'href':tg.url('/')
      Frontpage
  %div=unescaped(data)
  %a: 'href':tg.url('/edit', pagename=page.pagename)
    Edit this page


Posted by airportyh 9 months ago about haml, programming, python, rails and turbogears (0 comments)

capistrano and deprec

I got slicehost recently to host osspinions, and started getting into using capistrano and deprec to deploy the app and set up the box. You can think of capistrano as a remote control enabled make, and deprec as bunch of tasks build on capistrano that automates the setting up of everything from your user account to deploying your rails app - for ubuntu only. I was really impressed, just 4 commands installed everything up to the rails stack. But the deployment of the app was harder, a lot harder, in fact. I had to install ferret(which I just more recently ditched), FreeImage for image science, and rcov as a gem, and ruby-openid as a gem as well. These things are the ones that I could not stuff into the vendor directory and have it work. After that, for ferret I had to use symlinks to share the index directory, and for uploaded files I had to symlink them too because the deprec setup is such that every deployment you do creates a brand new directory for the new release. This is good in many ways, but it also creates some complications. I heard the guys on the slicehost podcast talk about this and they pretty much confirmed as much: it's hard to make deprec work for everybody because everybody does things differently, Oh well. Capistrano, on the other hand, is pretty nice. I wrote a python script at my last job to build and deploy a Java app, and if I had came across capistrano then, I would have definitely used it instead and would have saved me a lot of work.
Posted by airportyh 10 months ago about deployment, programming and rails (0 comments)

Gigantic Rails Log File Slows Down App

My Wiki has been mysterious getting slower and slow and I didn't have a clue why. Today I happened to check the log file's size, it was over 10m. So I removed it and the Wiki was back to normal. Conclusion: you have to have a way to manage the size of rails applications. Some people just turn off logging altogether. I opted to set the log level to error. Another option would be to have a cron job remove the file periodically.

Update: Not so sure the large log file was the cause anymore. I still don't know what caused it, may a memory leak of some sort, or maybe this is just the woes of using a shared host. The problem hasn't come back so far, so I haven't been able to look further.
Posted by airportyh 10 months ago about programming and rails (0 comments)

Changing the rendering for displaying exceptions

I just added autofresh support for the stacktrace pages, now you get get the benefits of autofresh while you are refactoring your code, which can cause temporary breakage, for example. It was easy, altough not at first easy to find. The answer was found in the comments of actionpack/lib/action_controller/rescue.rb. It bascially said you just need to override the rescue_action_in_public - for "public" errors - and rescue_action_locally - for local errors, which shows the stacktraces. I just copied the existing rescue_action_locally method over and swapped in my template file instead(changed code in orange):

module ActionController
  class Base
    def rescue_action_locally(exception)
      render :text => 'it bombed'
      add_variables_to_assigns
      @template.instance_variable_set("@exception", exception)
      @template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub")))
      @template.send!(:assign_variables_from_controller)
 
      @template.instance_variable_set("@contents", @template.render_file(template_path_for_local_rescue(exception), false))
 
      response.content_type = Mime::HTML
      render_for_file("#{File.dirname(__FILE__)}/templates/layout.erb", response_code_for_rescue(exception))
    end
  end
end

This will tell it to find the layout.erb in my plugin directory instead of the one buried deep inside rails.
Posted by airportyh about 1 year ago about programming and rails (0 comments)

Autofresh

Out of frustration with the work I was doing, I decided to switch gears a tiny bit and work on this idea I had, and Autofresh was the result. I enjoyed this experiment, it did not take much to make it work - I just based it on the rspec_autotest plugin by Nick Sieger, but it turned out to be very useful, Yeh!
Posted by airportyh about 1 year ago about plugin, programming and rails (0 comments)