Showing posts with label Rails. Show all posts
Showing posts with label Rails. Show all posts

Monday, February 21, 2011

Laissez les bons temps rouler!

Starting on the day before Mardi Gras, I will be joining EdgeCase working in their Cincinnati office. To me, a much bigger party than they'll be having in the French Quarter!

This is a phenomenal opportunity, working alongside the genius of Jim Weirich and Scott Barron every day, and collocated with the Gaslight Software crew. (Let me tell you, this is a really smart room.)

Many thanks to Joe, Ken, Adam and Leon for taking the time to meet with me and make sure I'd fit there, and to everyone who's supporting me in this transition. To be sure, I'll miss the folks I've been working with, but I'm ready to get cracking on new stuff!

Thursday, August 27, 2009

The Missing Link in RJS Chaining

One of the things that make Ruby and Rails my respective current language and web framework of choice is the collective ingenuity that has made building things easy. These folks have thought of everything, gosh darn it, and I get to use it. A good day is when I get something working, and with Ruby and Rails I have a lot of those days.

Imagine my dismay however, when on a recent project I had the need for something that wasn't already baked into Rails! The problem occurred when chaining partials together - one partial calling another, calling another, and so on down the line. I find myself doing it a lot these days, updating many parts on a page based upon seemingly simple model changes. Chaining partials together is easy, you just set up some context and render, and repeat.

Using Ajax and RJS is now a way of life; I got my baptism in the Javascript waters a long while back, a must for doing esoteric, dynamic rendering. RJS certainly isn't what makes such rendering possible, but it sure makes it easier. Some may think that there are better mechanisms - and maybe in special situations there are - but the simplicity and versatility of generating pieces of web pages using RJS is unparalleled once you understand the subtleties of building Javascript that will be executed in the context of a page.

Context is the issue. Let us say my foo partial renders my bar partial. The context is established as a hash of variables to values that is built by foo and passed into bar as the value of the :locals key in the render call. When bar is rendered, the hash is unraveled behind the scenes and the variables become available.

All except one, that is: the meta-variable that is the locals hash itself!

Unless I'm missing something, when you want foo to pass whatever locals it had received to bar, Rails comes up short! There's no way that foo can know all the variables that got passed in because this information is lost. The hash has been absorbed and is no longer part of the context! The variables in the locals hash that were set up by foo have been unpacked and established as the context of bar, but the containment itself is no longer available.

An argument might be made that making the locals hash available would be wrong; if the code knew it had the locals context, partial-coupling might be considered to be too tight. Perhaps so, but I'd say this really isn't true - assuming context in the form of injected variables is really at the same level of coupling. After all, what Rails is doing for me is just saving me some coding by allowing me to access a variable directly instead of as locals[:variable] if the incoming locals hash were exposed. The way I see it is that permitting a partial to access the incoming locals hash is actually promotes less coupling. A partial could just pass, augment and pass, or create and pass a new hash to the partials it calls - not necessarily knowing to what use the information in the hash might be put, or which partial down the line might be using it.

Chaining is about delegating responsibility - entities at intermediate levels really shouldn't have to be concerned with the details of what's happening above and below them. They should be able to pass information along with the understanding that if they don't need it, that doesn't mean that something further along the chain won't. If there's any doubt about this perspective, consider that partials are simply about rendering a page - the page is the real context and many complex renderings of application state changes may be made upon receipt of a seemingly simple event. That's what RJS is really good for - making multiple coordinated changes to a page. Allowing information to be passed down from on high so chained partials can use it according to need in the context of rendering different parts of a page is exactly why RJS is so sweet. Forcing intermediate partials to know what their subordinates need makes them difficult to write, hard to test, and downright painful to change.

Of course, just because this isn't automatic doesn't mean I can't do it myself. Passing foo a reference to the :locals hash as the value of the :local_assigns variable in the :locals hash it receives itself, for instance, allows me to pass it as the :locals hash to bar. Not a great solution, and it smells a little. Yes, it does mean I have to do some extra work, something Rails has helped me to otherwise avoid, but I can put up with this. Sigh. I sure wish the locals hash was already exposed - it is the missing link for chaining.

Bottom line: not having access to the incoming locals hash in a partial is a bummer, but it isn't the end of the world.

Thursday, March 05, 2009

Why Can't We All Just Get Along?

While building a browser-based graphical editor in Rails for a client, I ran across an cross-technology compatibility problem. The reason was not immediately apparent and caused me quite a bit of head-scratching. After sleeping on it for a night, I finally figured it out and found a workaround.

In the graphical editing app that I'm building, one of the things a user does is create selections of items. When selecting, shift-clicking on an item toggles it in or out of a selection. I use SVG to represent the items being edited in the browser and manipulate them using Javascript.

Building composite graphical elements is made easier by using the SVG use element since this can encapsulate each part, setting up display and event handling for each in a compartmentalized way, and the code for representing the parts can be shared across items. An item may reference many use elements in its representation. These elements are then added to the document and displayed automagically in the browser. Javascript functions handle the events targeted at the items.

Everything's good so far. Simple SVG elements can be manipulated easily by the Javascript, and AJAX calls are sent to the controller to update the model. Shift-clicks toggle items in and out of the selection as expected. But shift-clicking an element that includes a use element in its definition (in my case, a path element is being referenced by another element) causes a new graphical editing window to be opened in addition to the toggling.

What the heck?! Debugging the Javascript in Firebug shows that all of the expected things are happening correctly and the code is running cleanly. Yet as soon as the code finishes, up pops a new window. I'm certainly not firing a request to do this. What's going on?

It turns out that Firefox implements shift-click-on-a-link functionality that will open a linked reference in a new tab or window. This is extremely useful - I do it all the time when I'm browsing. But it didn't occur to me that this behaviour transcends normal event handling! I need different behavior in my editor!

It turns out that the way that SVG support is built in, shift-clicking on an SVG element that's drawn with the use element is misinterpretted by Firefox as a request by the user to follow the link embedded in the use element. But this reference is meant to be invisible - SVG uses these reference to display graphics, not to expose clickable links.

This wouldn't be so bad if there were a way to tell the browser that the event has been handled and not to do the default shift-click-on-a-link functionality. Normally such things are done by halting the propagation of events. Alas, for the shift-click, this has no effect. It appears that it is not possible to stop this behavior through Javascript. There may be a way, but I couldn't find it.

It's not a bug in the browser. It's not a bug in SVG. It's a bug that emerges when the two technologies come together. If the browser didn't hide access to its shift-click behavior, all would be well. Or if SVG didn't use the html linkage mechanism to do element referencing, all would also be well. But shift-click is inescapable in the browser and the element referencing is as it is in SVG. The bug is in the space where they overlap.

The workaround is not to use the use element in SVG if such elements can be shift-clicked. This causes the size of scene representations to balloon when the items are complex, but at least they can respond appropriately to events. The fix is to make Firefox (and whatever other browsers exhibit this problem) understand the difference between internal and external referencing via linkage in SVG.

Emergent bugs like these are insidious. It is the clash between multiple context-free systems that occupy the same technological space that lead to such problems. I predict they will appear more frequently as we move forward and continue building embeddable software. The best we can do for now is to fix or workaround the problems as they are found as I have here.

The bottom line is that we must recognize that in the areas where context-free systems that are used together overlap there will be ambiguity. The composite behavior of these systems must be considered and dealt with appropriately, either through code or policy. It's not clear that we'll ever be able to find all of these overlaps prior to encountering the problems they cause; I just hope the scenarios in which the problems occur aren't too dangerous.

Wednesday, November 26, 2008

Users, Roles, Rights and Sights

Chad Fowler's Rails Recipes book lays out authorization as the interrogation of the many-to-many connections between users and roles, and between roles and rights, a right being a named controller-action pair. The many-to-many relationships are established using roles_users and rights_roles tables in the database.

This indirection makes bulk assignment of rights easy, simply by assigning roles to a user, and authorizing using nested detection:
class ApplicationController
before_filter :check_authorization
def check_authorization
unless @operator.roles.detect{|role|
role.rights.detect{|right|
right.action == action_name &&
right.controller == self.class.controller_path } }
flash[:notice] =
"You are not authorized to view the requested page"
request.env["HTTP_REFERER"] ?
(redirect_to :back) : (redirect_to home_url)
end
end
end
Here, @operator is the user that is operating the application.

This works fine, but the interrogation of rights seems a little too removed from the user. I prefer asking if a user has a particular right directly:
class User
def has_right?(controller,action)
rights =
User.find_by_sql [
"select * FROM rights ri, rights_roles rr, roles_users ru where"+
" ru.user_id = ? and ri.controller = ? and ri.action = ?"+
" and rr.role_id = ru.role_id and ri.id = rr.right_id",
id, controller, action ]
rights.size > 0
end
end
I also took the liberty of dropping the in-Ruby detection since a single sql query is faster than the multiple smaller queries that detection requires (look at the log files - one query for each role.)

So this is a bit faster and is a drop-in replacement for the detection in the original code:
class ApplicationController
def check_authorization
unless @operator.has_right?(self.class.controller_path,action_name)
flash[:notice] =
"You are not authorized to view the requested page"
request.env["HTTP_REFERER"] ?
(redirect_to :back) : (redirect_to home_url)
end
end
end
Besides simplifying the authorization, since has_right? is a method of a User, any user's rights can be simply interrogated, which useful in setting up rights administration for an application.

Formulating the right-checking in this way also leads to the notion of sight-checking, that is checking if a user has the right to see something. For instance, when building out a page if there is a question as to whether or not a user is allowed to see something, a sight can be established that allows it to be seen. The absence of a requested sight in the rights table for that user's roles implies that the user should not see the sight.

Sights don't necessarily depend on controller-actions; typically they're just checking to see that the user has a right with a particular name. The code to check sights is a simple as that of checking rights:
class User
def has_sight?(name)
sights =
User.find_by_sql [
"select * FROM rights ri, rights_roles rr, roles_users ru where"+
" ru.user_id = ? and ri.name = ?"+
" and rr.role_id = ru.role_id and ri.id = rr.right_id",
id, name ]
sights.size > 0
end
end
Checking for sights looks for a Right's name, while checking for rights looks for a Right's controller and action. Moving the interrogation of rights to the user and adding the notion of sights allows pages to be constructed more simply based on what a particular user is allowed to do.

Wednesday, October 15, 2008

Enhancements to Railroad

A picture is worth a thousand words, and is certainly easier to talk about than reading a bunch of code. At least for me.

On a recent Rails project two dozen models and sixty associations were needed to drive the application. A medium sized effort. However, it's tough to talk users through the complexity when the need arises, even when you're just dealing with a small chunk. After drawing circles and arrows on whiteboards too many times, I decided to mechanize.

I'd used Railroad (a great rubygem written by Javier Smaldone) a few times before to document smaller projects. It loads models and controllers from a rails project and renders everything in 'dot' format that can be processed by graphviz, an open source graph rendering framework. I railroaded the app and quickly had diagrams in hand. Happiness all around.

But there were a few things I noticed as I talked around the pictures. I needed colors. And labels. And fewer circles and arrows. I decided to take a dive into the railroad code and add some features.

What I eventually ended up with was a considerable set of changes.

Changes to Allow Subgraphing

Often I didn't want to see the whole graph at once. What I wanted was the ability to include only the models I listed, or exclude a set of models from the whole. After implementing this, I decided I also wanted the ability to focus on a set of nodes, including them and any other directly-connected nodes.

  • I added support to only include model classes in a diagram by name specifying -I class1[,classN] on the command line.
  • I added support to exclude model classes from a diagram by name using -E class1[,classN].
  • I added the capability to focus on a set of model classes. By specifying -F class1[,classN] on the command line, only these nodes, the nodes they connect to, and the associations between them are displayed. However, this is also subject to any additional model class exclusions (-E) or inclusions (-I) that are specified.

  • By using -F, -E and -I in combination, a logical subset of the model can be displayed fairly easily.

    Model Node Content Display Changes

    I found that I sometimes needed more or less information in a displayed node. Brief mode was already present (for just displaying the class name in a node) but I wanted a little more content control.

  • I changed the display of magic fields in model nodes to be off by default. Before, you'd hide the magic fields by specifying --hide-magic on the command line. I added a --show-magic option to turn them on instead.
  • I changed the display of association fields in the node to be off by default, shown only by specifying --show-assoc-fields on the command line, and label them with the name of the associated model.
  • I added a -B option to display all nodes as brief except focused nodes (those specified with -F).

  • Using -B with -F turned out to be a great way to present information. I could see what was being focused upon in context, without extraneous detail.

    Changes to Association Display

    I found I needed to be able to show different associations differently. Conventional Rails associations were fine, left black and unlabeled. But polymorphic associations, many-to-many through relationships, and unconventionally named associations needed different labels and colors. By default, I decided to always display these and provide methods to hide them.

  • Unconventional associations and their labels are blue; navy blue if only one side of the relationship is unconventional. The labels are hidden by specifying --hide-uaslab on the command line.
  • Polymorphic associations and labels are red. The labels are hidden with --hide-paslab.
  • Through associations and labels are dark green. The labels are hidden with --hide-taslab.
  • For convenience, all association labels may be hidden with --hide-aslab.

  • Multiple Diagrams at Once

    Once the rest was done and I'd used it all for a while, I decided that automatically generating a focused diagram for each model would save me a lot of time.

  • I added support to create a focused diagram for each model class in its own dot file using -O FILE. The output file name for each model is created as FILE.dot, and FILE may include directory separators.

  • A simple rake task completed the automation:
    @railroad_command = Config::CONFIG["target_vendor"] == 'pc' ?
    'railroad.bat' : 'railroad'
    task :graphs do
    FileUtils.mkdir_p 'graphs'
    `#{@railroad_command} -M -b -o graphs/_overview.dot`
    `#{@railroad_command} -M -B -O graphs/`
    FileUtils.cd 'graphs' do
    FileList['*.dot'].each do |f|
    `dot -Tpng #{f} -o #{f.gsub(/dot$/,"png")}`
    end
    end
    end
    Finally, I refactored the completed code, DRYing out the iterative changes I'd made.

    What I now have is a nice, simple way to produce diagrams of the database and associations between tables for discussion and documentation. I submitted the patch to Javier and hopefully it will be integrated into the railroad trunk fairly soon. You can grab railroad-0.5.0 and the patch and play with it if you want by downloading it from rubyforge.

    Tuesday, September 23, 2008

    Installing Rails Plugins from Local Sources

    I'm usually reluctant to go change "big things", almost always prefering to work around any issues I encounter. On the rare occaision though, I find I really must make changes or I'd forget what I did and struggle with it again later.

    The script/plugin install command in Rails is a wonderful thing. It fetches code from repositories (like subversion or github) and installs it into your Rails application. Plugins generally extend Rails' capabilities, much in the way that Ruby is extended through Rubygems. However, the plugin installer assumes a repository, or at least the web. If there is a local copy of the plugin in your environment that you'd like to use as the source, you're out of luck. You have to do the install by hand, and remember to set up some environment specification. There's just no provision for local installs.

    Necessity being the mother of invention, when I found myself needing to install a plugin from local sources, I tried to find a workaround. When I could find nothing satisfying, I did some editing. A very slight amount of editing. In ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/commands/plugin.rb

    class Plugin
      def file_url?
    @uri =~ /^\//
    end
      def install(method=nil, options = {})
    method ||= rails_env.best_install_method?
    if :http == method
    method = :export if svn_url?
    method = :clone if git_url?
    method = :file if file_url?
    end

    uninstall if installed? and options[:force]

    unless installed?
    send("install_using_#{method}", options)
    run_install_hook
    else
    puts "already installed: #{name} (#{uri}). pass --force to reinstall"
    end
    end
      private
        def install_using_file(options = {})
    root = rails_env.root
    mkdir_p "#{root}/vendor/plugins"
    Dir.chdir "#{root}/vendor/plugins" do
    cp_r @uri, @name
    end
    end
    end
    That is, if the specified plugin being installed starts with a slash, assume it's an absolute path to the directory that contains the plugin and fetch it by copying. Then the install can go along it's merry way.

    Now I can just fire off a
       ruby script/plugin install /Downloads/rails/plugins/foo
    and it will install the foo plugin in the specified directory into my Rails project, just as if it were out on the net.

    This certainly may not be perfect, and if I were polishing it I'd add a check for a "file:" protocol and include relative paths, but this was just enough for my needs.

    Friday, August 15, 2008

    Rails, Prototype, Ajax and Forms Walk into a Bar...

    Rails is my friend. Prototype is my friend's foreign friend. Ajax is my child-prodigy friend. Forms is my long-time blue-collar friend. Submit buttons are pieces of currency, among many other Internet coins and bills. Recently my friends and I got together at the local web bar to have a beer.

    Rails, Prototype and Ajax had been hanging out together lately, and while it seems they knew Forms fairly well, he was kind of old. The other three were younger and getting rich, and so they'd started paying for everyone's drinks. Forms had been buying me beer for a long time, but hadn't had to pull out Submit Buttons very often in their presence since we met the other three. The other day, I asked Forms for a few Submit Buttons to get a beer, but Rails, Prototype and Ajax said they'd take care of it. Forms smiled and said "Fine. Thanks."

    I took the Submit Buttons up to the web's bartender, and to my surprise he said they were no good! They were skilled forgeries! They looked like the real thing, but the serial numbers were all the same!

    I went back to the table and told my friends. It turns out Rails had suspected they might not be good enough to pass before a scrupulous eye for a few years. Apparently Prototype had been giving them to Rails to help Ajax for a while. Forms pulled out a real Submit Button so I could hold it and the forgery up to the light and compare them.

    The deal is that if you use Rails to generate multiple submit buttons on a remote form (ie. for Ajax), regardless of which button is clicked, only the value of the first button is set in the parameters coming into the controller. The issue was documented by Ticket #5031 on Rails-Trac over two years ago. While there was a partial fix put into prototype in 2007, it didn't go far enough to fix the problem.

    I played with the prototype code a bit and roughed in a solution, but had an older Firefox on the machine I was using that was incompatible with the latest Firebug. My tests passed, but I was sure they weren't exhaustive. Since I couldn't see what was getting generated under the covers, I didn't trust it enough to use my fix and went back to the web to see what others had done.

    I found the solution that I decided to use on Harry's Blog, basically to tuck the value of the submit button that was pressed on an Ajax form into a hidden field. This is done by assigning the onclick of each submit button to some field-setting javascript code. Since this was essentially what I was doing under the covers in the prototype, I was happy.


    I sat down and changed the Submit Buttons Rails had given me out of the view of the web bartender. I then gave them to our server who brought me back a nice tall beer. Good times ensued.

    I haven't done any wholesale changing on either of my friends Rails' or Prototype's Submit Buttons yet and I hope to avoid it, preferring getting together with my friends in the more comfortable setting of my neighborhood web bar instead of submitting my changes to official scrutiny. For now I'll keep fixing the Submit Buttons locally and just let the officials get to it in their own time.

    Time for another beer, eh guys?

    Wednesday, July 16, 2008

    Running Fast and the Demise of Dynamic Scaffolding in Rails

    Sometimes things just get away from you. You get distracted, turn your head, and then when you look back everything's changed.



    "In this place it takes all the running you can do, to keep in the same place."
    - Red Queen to Alice in Lewis Carroll's Through the Looking Glass



    Admittedly I haven't been on the Rails edge for a while. My day job keeps me in Java, and my own work has been more focused on interfacing with FXRuby than through a browser. When I did use Rails, I used my older version and got along just fine.

    But over the last few weeks I decided to pull in the latest and greatest. A few minutes of Rails 2.1 Gem downloading, another minute to create an app framework, lay in a db design as a migration, create a controller and add the requisite scaffold call into the code, and give it a try...

    Dynamic scaffolding is no longer part of Rails. It was removed because it was considered detrimental - since scaffolding is intended to be temporary, it should be able to be easily removed. If the guts of scaffolding are dynamic, only being instantiated at runtime, you can't replace the scaffolding incrementally. It's all or nothing, which is hardly agile.

    Of course, in the upcoming third edition of Agile Development with Rails this all explained. In the old days (sic) of dynamic scaffolding, a change to the database table underlying an interface changed the interface. Though this is no longer the case, the book includes examples of how to change the code files manually. You add a few lines of code to a few different files and everything just works.

    This is great when you're changing polished code, but a pain when you're prototyping. When you're building the initial cut of an app and data model, you want to play before you do any polishing. Work on the big picture first! Adding code to a couple of different files is a burden at this point. Especially since every character you have to type has a relatively large potential to be wrong and slow you down.

    While I certainly don't expect to get dynamic scaffolding back (although I could use some alternatives - Streamlined or ActiveScaffold, for instance,) internally Rails does know how to produce the scaffolding code. It makes sense to be able to use Rails to generate the textual pieces of any new scaffolding so that they can be quickly cut and pasted into place.

    I don't really care how it's done - output to a file, or the screen, or grafted to the end of the migration as a comment, or whatever - but it should be done by Rails. I really don't want any specialized capability for producing missing scaffolding in an editor macro or template. Editors should be general purpose, requiring little to no maintenance. Putting the intelligence into macros and templates would force them to have to track the next changes in Rails. Cut and paste seems an optimal strategy in the face of losing dynamic scaffolding.

    Don't get me wrong. Removing dynamic scaffolding is clearly a good thing for all the reasons it was done. But in the spirit of writing less code, Rails should facilitate the development process by producing intended scaffolding on demand to be copied into place by the developer. This would make it quicker to "get things right" and keep any new scaffolding style-synchronized with the initially generated Rails scaffolding.

    Leastways, it couldn't hurt.

    Monday, June 23, 2008

    A Little Easier EasyLogging

    In need of easier access to thresholding, I added some more methods:

  • one to pull the current threshold level,
  • five to interrogate the current threshold with respect to a given level, and
  • five to set the current threshold level

    as they relate to the default logger. These are available as mixed-in methods on the EasyLog Module and class methods of EasyLogger class.

    Additionally, I added special support for writing empty log messages to aid in grouping related log entries.

    I extended the earlier paper with a description of their use, and have added them to in the eymiha_util-1.0.2 rubygem in my Chunks of Ruby Infrastructure project on RubyForge.
  • Tuesday, September 19, 2006

    Establishing Session Context

    I'm a big fan of context sensitivity. I'm also a big fan of Rails. Recently the two topics crossed paths in the guise of contextual overlap in the session of a large Rails application I've been building, and I decided to get rid of the headache. I've built some code to establish disjoint contexts in the session, transparent to normal Rails development.

    Feel free to take a look and comment...

    Saturday, September 09, 2006

    Domain Orientation and Rails

    Over the last two years I've switched my development target to web apps. Though it started earlier than this, while I was still building TekCAD I was purposefully writing Java and Swing to earn my rent. The transition to full-time J2EE work that I made was good, but when I started doing Ruby and Rails my application-building days got much better.

    Ruby and Rails are just vehicles, however. While they make it easy to put together new web apps, the opinionated style of Rails does not always jibe with what I've learned through experience about what end users expect. Users are domain experts. Given their expertise, They certainly don't look at problems the same way as application developers do. They want their complex understanding of a domain distilled into clever interfaces that save them as much effort as possible while still maintaining enough safety to keep them from making horrific mistakes. It's often quite tricky to develop these sorts of domain-expert applications, but that's what these users want. The raw-Rails philosophy enforces a certain perspective, focussing on exposing objects and enforcing rules and validation - however without considerable domain-bias worked into the application, the result can feel relatively flat.

    This should be expected. Rails is about building applications, not understanding domains. The two problems are orthogonal. Web applications that are domain-oriented can be realized in any web framework. Rails just makes building them easier for developers.

    As I've worked forward through these last two years, learning Rails with an emphasis on developing good domain-oriented applications, I find myself writing smarter and smarter controllers and depending more heavily on state stored in the session. This is somewhat contrary to the stateless mode preferred on the web, but I find it is typical for domain sensitivity. And surprisingly, I'm discovering some good new stuff.

    What's good is this: the switch to Rails has given me the opportunity to re-examine domain orientation. In the past I've had to work so hard just to get everything finished for everyone - what with slashed budgets, creeping features and accelerated schedules - that my consideration of domains as a thing unto itself has been myopic at best. It's hard to be philosophic when you don't have enough time for it. Only rarely have I had the chance to step back and look at the meta-level of domains with respect to application development. But Rails has given me more time. Now I am refactoring my thinking as I refactor my code. I'm beginning to see shapes coming into focus: fundamental principles are being revealed about what it means to build software enriched with domain specificity.

    Geekhood showing, I am salivating at the thought of capturing this knowledge. More is certainly to come...

    Monday, August 07, 2006

    Rails Aggregations Ready for Prime Time?

    Aggregation (or composition) of database fields into value objects in Rails has given me some fits lately. While a valuable abstraction, it unfortunately does not yet cohabitate nicely enough with the rest of Rails to make them painless.

    Using the example from section 15.2 in "Agile Development with Rails", a Name is a group of three fields (first, initial, last) that is used in a Customer. Great. The Customer uses the composed_of method and you can do things like name.first, name.last, and call methods you might define in Name. All is well... that is until you start using it in the framework, say for example for validation or within views.

    Let's say, for instance, that a name needs to be unique within your system. Not necessarily a completely valid constraint perhaps, but good enough for argument's sake. Well, you can't do a validates_uniqueness_of :name to indicate that you always have a unique combination of first name, initial and last name because the validation doesn't play nicely with composites. Names just don't expand correctly inside the validators - code to handle this case is still missing.

    Ok, let's consider views. say you want to use the last name in a text field - you can't specify because name.last isn't an attribute, although it's certainly standing in for one. The attribute string mapping is just not robust enough for within the framework.

    No, sorry, though aggregation is sweet, the mix within Rails isn't there yet. It's unfortunate since the mechanism could be so clean. To do what's needed today, you just have to slice up the problem differently and using composites outside of the model. I guess these are the growing pains that will shake out over time.

    Tuesday, July 25, 2006

    Tipping Points and Big Adventures

    In Malcolm Gladwell's year-2000 neo-classic, "The Tipping Point: How Little Things Can Make a Big Difference", the phenomenon of epidemics is explored. He explains how small events catalyze sweeping changes and discusses them in many different contexts.

    Many of us have been anticipating the Ruby and Rails tipping point to be close at hand. It is clear to me that this is happening now. The growth of use of the language and framework, the coverage in the press, new books appearing on the market, sell-out conference attendances - all are indicative that the knee in the curve has been reached.

    But different epidemics have different quantitative characteristics. There are many dimensions in which the epidemic manifold may lie, and the shape of the curving surface depends on many factors - what's important is unique to each epidemic. Gladwell helps his readers understand what tipping points are and why they occur, but doesn't give us ways to recognize what the small events were that enabled them except in retrospect.

    It is much easier to analyze a historical epidemic than measure an occurring one. Take the Asian bird flu and i-Pod as examples. Will bird flu be the explosive pandemic that the health officials have predicted? Has the knee-phase in the i-Pod curve been completely passed? How can such things be measured when it's not clear exactly which measurements are appropriate? I suppose that in absence of prescience, all we have is gut feels, educated guessing, and luck.

    The closet futurist in me says to the intrepid software developer in me that the Ruby and Rails epidemic is hitting. The wily entrepreneur in me is overhearing the conversation and wondering about timing, asking the mysterious gypsy in me to do a little gazing into the crystal ball. As I stand at the edge on the hill and look up to see the peak of the summit, I wonder which route will get me to the top and let me enjoy the best sights along the way. It is joyous to live in such fun, turbulent times.

    Tuesday, July 18, 2006

    All is not CRUD

    CRUD (Create, Retrieve, Update, and Delete) operations are the basis for virtually all record-oriented database activity. At RailsConf 2006, David Heinemeier Hansson, the opinionated creator of the Rails framework, argued that CRUD and the parallel operations in http (Post, Get, Put, and Delete) and Rails (Create, Find, Update, and Destroy) are all analogous. This is absolutely true.

    He went on to argue that in the context of web applications and http, if we "learned to stop worring and love CRUD" (making CRUD operations the only things that are going on in our contollers) the advantages of simplicity, free REST, etc. would all be had directly. Though this may be true, is it reasonable? Abstractly, it can be argued that manipulating objects only via CRUD is all that is needed. But the fact remains that real domain objects transcend records - from the user's perspective, all is not CRUD.

    The user has a wide view of objects and systems - essentially because they don't have to write programs that work with them. "Make it do this" is the universal cry of the user. User demand for more functionality delivered in novel ways - to make things easier to use and drive customer demand - is what makes software development a worthy pursuit. The constant fight against complexity and its simplification makes programming fun. Rails works towards simplicity by doing many of the repetitive tasks for you so you can get on with taming the domain complexity - the meat of the problems, the place where developers can have real fun. Users deal with domains; developers translate domains into software - the rest is extraneous. Domains are where the light of programming truly shines.

    While web application that is only intended to manipulate related records would benefit from the simplified CRUD view, my experience tells me that real systems are not so CRUDdy. Where more is expected from an object in a web app, there's a lot more going on in the controller than simple CRUD to access the richness of the models of the domain objects. True, real systems with real objects backed by records utilize CRUD at the low levels, but the domain is usually much richer, full of operations intended to make the user's - not the developer's - work easier to do.

    Of course, Rails won't force a pervasive CRUD view on it's users. They will be free to continue on as before, with relatively large controllers and complex models. I do think the CRUD emphasis has value, but I believe weight should also be given to the further simplification of domain modeling, and using rails to link systems with common domains together in the dynamic, post-modern ways that Martin Fowler asserted in his talk at the conference. Rails must continue to be a simplifier to move the new web-application reality forward.

    Monday, July 17, 2006

    RailsConf 2006 - Redux

    One of the most interesting things I noticed at the RailsConf 2006 (held in late June in Chicago) was the Java-bashing (mostly tongue-in-cheek) that was going on. This in itself was not unusual; the majority of the folks in attendance made the transition from J2EE to Rails. What surprised me was there was no .Net bashing - .Net is not even a blip on their radar.

    While this could mean many things, what it said to me was that in the bigger scheme of things the .Net school of web development is considered below the threshold of reasonability. Even though many developers are building in .Net, compared to the rest of the web-application development mainstream these are the unenlightened people that will learn the Rails-truth the hard way, when their customers or management start to question their productivity.

    Sunday, February 05, 2006

    Firefox and IE, and Rails Pain

    I'm doing some Ajax in Rails and I found some more weirdness in the behavioral differences between Firefox and IE. I've abstracted a few snippets of code that should illustrate the issue...

    I have a form that contains a table holding a cell with a select that fires some ajax on a change, and the input field that is the target of the ajax change in another cell. I know that I could do this differently, and clean the code up a bit too, but there's no reason this shouldn't work in my little chunk of web. For the sake of this example, I've got a Foo and a Bar. Both have a cost field. When editing a Foo, you can select a Bar by name it's cost is put into the Foo's cost in the edit.

    in foo/_form.rhtml I have:

    <table>
    ...
    <tr><td>Bar<td>
    <%=
    @bars = [["Choose Bar"]]+
    Bar.find(:all).map {b [b.name, b.id]}
    select(:foo, :bar_id, @bars, {},
    {:onchange => "new Ajax.Updater('foo_cost',
    '/foo/bar_changed/'+
    this[this.selectedIndex].value,
    {asynchronous:true,
    evalScripts:true});"})
    %>
    ...
    <tr><td>Cost<td>
    <div id=foo_cost><%=
    render :partial => 'cost' %></div>
    ...
    </table>

    in foo/fooController.rb I have:

    def bar_changed
    @foo =
    begin
    Foo.find(params[:id])
    rescue
    Foo.new
    end
    @foo.cost = Bar.find(params[:id]).cost
    render(:partial => 'cost')
    end

    and in views/foo/_cost.rhtml I have:

    <%= text_field 'foo', 'cost',
    'value' => @foo.cost.to_money %>

    Ok now, I have to admit that I got this working over lunch at the day job using <gasp> IE 6. But when I brought it home to dig into in Firefox, instead of the Ajax updating the chunk of stuff in the <div id=foo_cost>, the input field itself was extended - because it too had an id of foo_cost. Firefox can apparently replace inside anything that has an id, where in this case (at least) IE just does a div replacement. This appeared as a field within a field (within a field, etc.) every time I selected a new Bar.

    The quick fix, of course, is to rename the id of the div. No biggie. But it did catch me unawares, and made me scratch my head a little. In general, I prefer more choices than less, and Firefox gives me that little extra. But it also means I have to be careful I don't get id space overlaps. Your mileage may vary.

    Wednesday, January 04, 2006

    "Just Stay on the Golden Path"

    Jim Wierich and Scott Barron did excellent presentations on Rails at the XP-Agile Cincinnati User's Group meeting last night. Jim gave a rapid-fire intro to Rails, and Scott built an Contact Management app with Ajax support using test-driven development before our eyes.

    During Jim's talk, he buzzed on the phrase "The Golden Path" - Rails' standard way of doing things. This was echoed around the room a bit, and then again when somone asked Scott about how hard it was to do non-standard Rails configuration. He replied that it wasn't particularly hard, but with tongue-in-cheek he said that we should all try to "just stay on the Golden Path."

    A good night of great fun. And we'll all miss you, John Wilger.