Yehuda Katz is a member of the Ember.js, Ruby on Rails and jQuery Core Teams; his 9-to-5 home is at the startup he founded, Tilde Inc.. There he works on Skylight, the smart profiler for Rails, and does Ember.js consulting. He is best known for his open source work, which also includes Thor and Handlebars. He travels the world doing open source evangelism and web standards work.

Archive for the ‘Merb’ Category

Can’t we all just get along?

Following up on Ezra’s great post today, I wanted to throw out my thoughts on the topic.

Pretty much since I got started on the Merb project (which I did primarily to get an awesome mailer in; I spent a long time wrestling with ActionMailer on a corporate project), people have looked at the Merb project as competition for Rails.

Honestly, to some degree, we’ve fueled that by providing benchmarks and comparisons between Merb and Rails. And since our architecture is so similar, it’s only natural that people’s initial reaction upon looking into Merb is, “Why should I use this instead of Rails?”

The truth is, Merb scratches a completely different itch from Rails. Rails was responding to the almost comical amount of configuration needed to get started on the Java or PHP “stacks” at the time. Its siren song was in making as many common choices for you as possible so you’d be able to start building your app quickly and efficiently.

Rails was a massive success. It changed the way the world looked at web development. Struts 2 touts convention over configuration and Cake PHP is virtually a clone of Rails.

Today, Merb exists not to supplant those ideas, because we fundamentally agree with convention over configuration, the common usage of the MVC pattern, the use of RESTful resources, and a bundle of other things that Rails introduced to the world. Instead, our niche is making life easier for hackers, those who find themselves repeatedly delving into the framework itself to squeeze the last bit of performance or customization out of it.

It is true that we think there are concepts in Merb that are incremental improvements over Rails. But we are not unhappy when those things make their way into the Rails core. Last month, Ezra spent a week porting over Merb’s rack support into Rails, and I spent a day improving the speed of the Rails Inflector by an order of magnitude. We’d love to see our provides API make it back into Rails, and we’ve already begun to see Rails focus more on efficiency and speed in the past few months.

The fundamental difference between Merb and Rails, the one that will likely remain as the most salient features of Merb slowly find their way into the Rails codebase, is our emphasis on hackability, and the Rails emphasis on get-up-and-go. We do not see this as a competition; we see it as a way to widen the appeal of Ruby (the language that we all love), and to keep people who fell in love with Ruby through Rails from falling out of love with Ruby when their needs become more about squeezing the very last drop of performance and customization out of Ruby.

To that end, I intend to continue pushing improvements from Merb back upstream to Rails. Some of them, like my Inflector change, will likely take some time to make it all the way back to the Rails trunk because they may break backwards compatibility, but the patches will be sitting in my github repository for the next backwards-compatibility breaking release :)

Let’s all be friends!

Ruby will be better for it.

Merb 0.4 — The One That Rocks!

So I’ve been talking quite a bit about Merb on my blog, and for those of you who could care less, I apologize. The Merb 0.4 pre-release will be coming out tomorrow, and I wanted to preview some of the really need features that have been added since 0.3.7.

  • Generators: Thanks to DrNic’s rubigen, we have full-fledged generators now. But it gets better. Our generators use the ORM and Testing framework you’re using to generate specific files that are appropriate. So if you do script/generate model Foo and are running DataMapper with RSpec, you’ll get new model files for DataMapper, and new spec files for RSpec (same with ActiveRecord, and Test::Unit, of course).
  • Parameterized Actions: If you specify parameters in your action methods, incoming query parameters will automatically get assigned as appropriate. Some examples:
    class Foos < Merb::Controller
      def index(id, search_string = "%")
        @foo = Foo.find_with_search(id, search_string)
      end
    end

    Going to /foos/index/12 will call the index method with the parameters "12" and "%" (the default provided). Going to /foos/index will throw a BadBehavior error (status code 400) because id is a required parameter, but it was not passed in. Going to /foos/index/5?search_string=hello will call the index method with parameters "5" and "hello". The bottom line is that you get to use your actions like real methods. Of course, the params hash is still available and is provided untouched.

  • Great Exception Handling: When an exception is raised inside a Merb::Controller, it is automatically delegated to the Exception Controller, where you can easily specify special behavior or custom templates. Since Exceptions are now just actions inside a controller (a NotFound error renders Exception#not_found), you can take advantage of layouts, helpers, filters, and assigned variables in your error screens.
  • Awesome Developer Mode stack traces: The developer mode exceptions all render a stack trace, in which each line is both clickable (and will pull up the affected file in Textmate) and expandable (you can get a quick overview of the surrounding lines of code without having to open up your editor)
  • Great content-type negotiation: Instead of laboriously doing a respond_to for every action, for each content-type, you can use strong declarative syntax and sensible defaults to slim down your controllers:
    class Users < Merb::Controller
      provides :xml, :json
      def index
        @users = User.all
        render @users
      end
    
      def show(id)
        @user = User[id]
        render @user
      end
    end

    The example shown above uses DataMapper, but the idea is simple. You declare, in your controller, which content-types will be supported. Then the browser sends the requested content-type (either via the content-type header or by specifying a file-type extension such as .json).

    When the action is called, Merb first checks if the content-type requested is available (and throws an error if it is not). When render @users is called, Merb first looks for index.json.erb (if, for instance, JSON is requested). If a template is not found, Merb calls @users.to_json. So in this example, you would simply provide an index.html.erb, and let Merb call @users.to_xml and @users.to_json for the other content-types.

    No more messing around with respond_to; the framework handles all the content-type negotiation for you!

While you're at it, feel free to take a look at my Why Merb? document, which goes into more depth about the architecture of Merb, and why you should use it!

That's a fair roundup of some of the coolest new features in Merb 0.4, and there's more to come on both my blog and others in the days to come. Enjoy!

Conferences, etc.

As some of you may know, I was at The Ajax Experience conference last week, along with the one-day mini-conference, jQueryCamp.

This was my third The Ajax Experience, and there were a lot of great people to see. Even more exciting though, was jQueryCamp, despite forgetting my t-shirt in Boston.. The accommodations were especially wonderful ;) (that’s code for… I crashed on John‘s couch. Thanks John!)..

I met most of my fellow core team members, which I’d really been looking forward to, along with a slew of jQuery geeks and gurus. Karl, Jörn, Bradley, Marc, Paul, Rey, Richard — just to name a few. I hope to post more about jQuery camp — the talks, etc. — when things get a bit calmer… if ever they do.

(As a side bonus, there were a few Merb folks around — what more could I ask for?!)

There was a pleasantly enthusiastic response to jQuery in Action; lots of people with comments, reading the Early Access version, and lots of people looking forward to it. I’m feeling good about it!

I’ll be at RubyConf in NC this weekend. There are a lot of people I’m looking forward to meeting there, and talks of some Merb hacking.

There’s nothing like putting faces to the IRC folks I talk to every day, the blogs I read, etc. There are also some old friends I’m looking forward to seeing again. Stephen Bristol, ReinH, Evan Phoenix, Jeremy McAnally, Ezra Zygmuntowicz, Dr Nic Williams, and so on. Leah (the wife) will be joining me at RubyConf too, so that’s always a bonus — and I know there are lots of people she’s looking forward to seeing too.

Do drop me a line, or comment, if you’ll be around. Would love to see everyone. Safe travels!

Merb Plugins? Oh yeah… they’re pretty frickin’ cool too

So there’s something kind of weird about having an entire plugin system depend on scraping a wiki page and subversion, but it doesn’t have to work that way. See, Ruby already has this great packaging system called gems. They have built-in version control, dependencies, and a distribution model. The only flaw is that actually putting a gem together was formerly a difficult process.

With that as a preamble, let’s dive into how Merb plugins work. Let’s start with how you make a plugin:

Making a Plugin

merb ––generate-plugin merb_foo

Note the prefix “merb_” — it’s not mandatory, but is highly recommended that merb plugins be prefixed with merb_, since they will be living in the gemspace with many other, similarly named gems.

Next, go into Rakefile and modify the metadata at the top for the plugin’s name, version, and so on. Throw your name into the LICENSE (by default, MIT), and update the README.

Inside of merb_foo.rb, you get a block that tests whether we’re running inside Merb. For plugins that require Merb, make sure to pop your code inside there.

Merb automatically provides you with a config hash in the Merb::Plugins.config[:merb_foo], which you can use to pass information from your plugins back into Merb, and vice versa.

Finally, you can use Merb::Plugins.add_rakefiles to add any rakefiles you would like to get added to the Merb app. It’s all pretty simple, and everything is blocked out and commented for you.

Once you’re done, you can do rake package and get your gem all made. Install/release the gem using normal install/release procedures, and then…

Using a Plugin in Your App

This part is ridiculously simple. There’s a file in your generated Merb app called config/dependencies.rb. Inside it, you’ll run:

dependencies "merb_foo", "merb_bar"

or

dependencies "merb_foo", "> 0.5"

or

dependencies "merb_foo" => "> 0.5", "merb_bar" => ">= 0.6.1"

Any of these will work. Dependencies are loaded before the app is loaded in. If you need a dependency to wait until after the app has loaded, you can enclose it in the Merb::Server.after_app_loads that’s already provided in the generated dependencies.rb file.

One more thing…

While it’s nice to be able to just use gems for everything, you might want to burn your plugins into your app for easy deployment. If that is what you wish, your wish is our command. In the root, simply run:

gem install merb_foo -i deps

That wonderful, already existing command, will install the gem into the deps folder in your app. Through the magic of Merb, the deps folder becomes an alternate gem repository, so you can deploy the merb directory to a remote server (even without access to the gem repository), and it’all Just Work. Cool huh?

Merb’s Parts are pretty rocking too

Once upon a time, there was a thing called “Rails Components.” They were heavyweight and nobody used them, so the powers that be took the axe to them. They live no more.

That said, there is a real need for a lightweight component system in MVC frameworks. Something that:

  • works like Rails partials, in that you can reuse common, existing code
  • use existing controller variables like params and session to do different things on the basis of what’s happening in the current request
  • most importantly, not force you to give up the C in MVC simply because you want to reuse some code outside of a single controller

Merb parts are the simple answer to that problem. First of all, Merb parts work just like Merb controllers; you get a new filter stack, layouts (if needed), and the full gamut of render functions that you have in normal Merb controllers. You also get to share all of the regular controller variables (request, params, cookies, headers, session, response). And because Merb’s philosophy is to have actions return strings, you can use the render methods, or any other string manipulation in your action, without fear of running into a “double-render” issue.

Here’s a simple example:

class Foo < Application
def foo
render
end
end

class Bar < Merb::PartController
before :foo

def foo
@x = 1
end

def baz
render
end
end

app/views/foo/foo.erb
<%= part Bar => :baz %>

app/parts/views/bar/baz.erb
<%= params[:hello] %>
<%= @x %>

In the example above, the view in the controller proper calls out to the part. The part runs just like a regular controller, so it has a before filter, which sets the @x instance variable to 1. It then calls the baz method, which renders its action. In the action, you’ll have access to the params from the original controller. You’ll probably want to handle that stuff in the part controller, but this just demonstrates that it percolates all the way down.

Because parts reuse the existing controller stuff, they’re very fast, and not the red-headed stepchild of controllers. Just like mailers, we benefit from the existence of AbstractController, which gives us the full filter stack, the ability to throw to stop the filter (and return an associated string as the result of the part), and all the other niceties of controllers.

Good stuff, huh? I have some more things to post about Merb, but soon… a comprehensive example!

Merb’s Mailer is Awesome (if I do say so myself)

A few months ago, when I first took a look at Merb, I noticed a distinct lack of support for email. There was a simple wrapper around MailFactory (a Ruby library that is, imho, superior to TMail, and actually documented to boot), but nothing like Rails’ ActionMailer.

That said, ActionMailer suffers from some very serious deficiencies, which makes most Rails users rue the day when the pointy-headed boss throws some “simple” mail requirement at them. In fact, while most Rails users expect writing mails to be roughly equivalent to writing regular controllers and actions, ActionMailer barely resembles the much more manicured ActionController.

In fact, the company I work at Procore, maintains what is essentially a fork of ActionMailer with some of these deficiencies resolved. The problem is that because we dig deep into Rails internals, a Rails upgrade also requires tweaking to our fork.

Some simple examples:

  • ActionMailer “controllers” go in the models directory, but their views are mixed in with regular views
  • ActionMailer instance variables are not assigned and passed into ActionMailer views
  • ActionMailer does not support layouts
  • While ActionMailer does support some simple magic with mime-types, if you do anything that is not exactly the default, you are required to specify the parts of your email using tortured syntax.
  • The ActionMailer syntax for attaching files is also a bit tortured and not particularly well documented:

      attachment “application/octet-stream” do |a|
      a.body = attachment2.data
      a.filename = attachment2.name
      end

So my agenda was to clean up all of these pain points, in the context of a brand-new Merb::MailController. At the time, there was no way to subclass the base Controller class without getting all the request gunk along with it, but Ezra was more than willing to create an AbstractController class, which contained the parts of the Controller mechanism that were not related to request-handling.

It turned out to be a good deal, because Ezra later used it to create Merb’s “Parts,” partials that also have the lightweight AbstractController implementation along for the ride (more on that in another post).

With the AbstractController up and running, I proceeded to hack together a MailController implementation. Merb::MailController:

  • controllers go into the app/mailers directory.
  • views go into the app/mailers/views directory.
  • instance variables are assigned to their views, just like any other Merb controller.
  • supports layouts by default, just like any other Merb controller. Layouts go in the app/mailers/layouts directory.
  • supports HTML/Plaintext emails very well.
    • render_mail :text => :foo, :html => :bar will look for a foo.text.ext and a bar.html.ext. If either is not found, it’ll fall back to just foo.ext and bar.ext
    • render_mail :foo is the equivalent of render_mail :text => :foo, :html => :foo
    • render_mail is the equivalent of render_mail :text => :foo, :html => :foo when you are inside the :foo action
    • If you pass a string instead of a symbol in, it will render the actual string, so you can use regular render methods (since Merb render methods just return a string).
      Example: render :text => "FOO", :html => "&lt;p&gt;FOO&lt;/p&gt;"
    • You can also mix and match: render :text => "FOO", :html => :bar
    • Finally, you can also do stuff like render_mail :template => {:html => "foo/bar", :text => "foo/baz"}
  • supports attachments trivially:
    • attach File.open("foo")
    • which is the same as attach "foo"
    • attach [File.open("foo"), File.open("bar")]
    • which is the same as attach ["foo", "bar"]
    • attach File.open("foo"), "name_i_want_to_call_it"
    • attach [[File.open("foo"), ["name", "image/png"]], [File.open("bar"), ["bar_name", "application/octet-stream"]]]
    • which is the same as attach "foo" => ["name", "image/png"], "bar" => ["bar_name", "application/octet-stream"]
    • attach StringIO.new("Some data I want to send"), "the_file_name"
    • attach StringIO.new("Some data I want to send") => ["the_file_name"], StringIO.new("More data") => ["another_file"]
    • Because Merb already includes Mime::Types, you do not have to include a mime-type unless you want to override the default. Merb will automagically determine the mime-type and pass it along.

      This means that the most common case will be something like attach "foo", which will simply attach the file in the file-system called “foo”, with the name “foo”, and its mime-type based upon its file-type. And multiple-files is no more complex: attach ["foo", "bar"], which will do the same for both files.

The bottom line is that all the major pain-points in ActionMailer are closed up. And this is all done in 79 lines of code, thanks to Merb’s excellent architecture. In fact, this is a testament to the general excellence of the Merb architecture. Merb is not “a lightweight Rails”, as many often say.

It is true that it’s lightweight, but it’s not true that it’s missing giant swaths of useful features (and this will become less and less true as people start to write plugins for merb, which will provide functionality like Rails-style form helpers that are currently missing). In fact, there are a number of cases, like mail support, where the Merb version is dramatically more functional.

Archives

Categories

Meta