Rails 3.0’s ActiveModel: How To Give Ruby Classes Some ActiveRecord Magic »

Created at: 13.01.2010 18:46, source: Ruby Inside, tagged: Cool Ruby on Rails Tutorials

activemodel.gif One of the biggest benefits of bringing Merb developer Yehuda Katz on board to work on Rails 3.0 has been his relentless pursuit of extracting out all of Rails' magical abilities from their monolithic encasings and into separate, manageable chunks. A case in point is ActiveModel, a new library that provides the model related parts of ActiveRecord but without the database requirements.

Get Rails-like Model Behavior on Any Ruby Class

In extracting the model-building parts of ActiveRecord, ActiveModel makes it possible to add model-like behavior to any Ruby class, with no Rails or databases required. In his latest blog post, ActiveModel: Make Any Ruby Object Feel Like ActiveRecord, Yehuda shows off how to get Rails-style models with validations, serialization, callbacks, dirty tracking, internationalization, attributes, observers and all the other Rails goodness.

Example Code

I've taken Yehuda's main example of using ActiveModel on a non Rails class and extended it with some code that actually uses the model:

require 'active_model'

class Person
  include ActiveModel::Validations

  validates_presence_of :first_name, :last_name

  attr_accessor :first_name, :last_name
  def initialize(first_name, last_name)
    @first_name, @last_name = first_name, last_name
  end
end

a = Person.new("Fred", nil)
a.valid? # => false
a.last_name = "Flintstone"
a.valid? # => true

Installing ActiveModel

If you're interested in ActiveModel and not so much in Rails 3.0, installing it is reasonably easy (though not as easy as only installing a gem just as yet):

  1. Go to or make a temporary directory
  2. git clone git://github.com/rails/rails.git
  3. cd rails
  4. rake gem
  5. gem install activesupport/pkg/activesupport-3.0.pre.gem
  6. gem install activemodel/pkg/activemodel-3.0.pre.gem

Once this is all done, the code example above will work.

As an aside, if you fancy having a go with the full pre-release (a.k.a. "pre") version of Rails 3.0, check out Dr Nic's slightly out of date but otherwise useful guide.


more »

Rails and Merb Merge: The Anniversary (Part 1 of 6) »

Created at: 24.12.2009 00:30, source: Engine Yard Blog, tagged: Technology merb rails Ruby on Rails

A year ago today, we announced that Rails and Merb would merge. At the time, there was much skepticism about the likelihood of the success of this endeavor. Indeed, The most common imagery invoked by those who learned about our plans was a unicorn. At RailsConf last year (well into the effort), both DHH and I used unicorns in our talks, poking fun at the vast expectations we’d set, and the apparent impossibility of achieving everything we’d said we wanted to achieve for 3.0.

A year has gone by, so it’s a good time to reflect on how well we’ve done at achieving those expectations. Over the next few days, I’ll take each bullet point that I provided in my original post, and go into detail about the progress we’ve made on that front.

I’ve given a few recent talks on these topics, so some of you may already have seen some of this, but I wanted to get it down in writing for those who hadn’t. I’ve also added new information, some of which was omitted because it was difficult to explain in a talk, and some of which is too current for any of my recent talks.

Modularity

Rails will become more modular, starting with a rails-core, and including the ability to opt in or out of specific components. We will focus on reducing coupling across Rails, and making it possible to replace parts of Rails without disturbing other parts. This is exactly what Merb means when it touts “modularity”.

We’ve spent a significant amount of time on this step which has been really fruitful. I’ll give a few specific examples.

ActiveSupport

First, we’ve gone through ActiveSupport, making it viable to cherry-pick specific elements. This means that using ActiveSupport’s inflector, time extensions, class extensions, or anything your heart desires is now possible without having to personally track the dependency graph. Here’s an example of what I mean, from the to_sentence method in ActiveSupport from Rails 2.3:

module ActiveSupport

  module CoreExtensions

    module Array

      module Conversions

        def to_sentence(options = {})
          ...
          options.assert_valid_keys :words_connector, :two_words_connector, :last_word_connector, :locale
          ...
        end
      ...
    end
  end
end

As you can see, to_sentence has an implicit requirement on assert_valid_keys, which means that in order to cherry-pick active_support/core_ext/array/conversions, you are forced to work through the file, find any unsatisfied dependencies, and be sure to require them as well. And of course, the structure of these dependencies could easily change in a future version of Rails, so relying on what you’d found would be unsafe. In Rails 3, the top of that same file looks like:

require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/inflector'

This is because we’ve gone through the entire ActiveSupport library, found the unsatisfied dependencies, and made them explicit. As a result, you can pull out the specific libraries you want for a small project, and not get the full weight of ActiveSupport.

Even better, other parts of Rails now explicitly declare the dependencies they have on ActiveSupport. So for instance, the code that adds logging support to ActionController has the following lines on top:

require 'active_support/core_ext/logger'
require 'active_support/benchmarkable'

This means that all of Rails knows what parts of ActiveSupport are needed. For simplicity, Rails 3 ships with all of ActiveSupport still provided, so you’ll be able to use things like 3.days or 3.kilobytes without interruption. However, if you want more control over what gets included, that’s possible. You can declare config.active_support.bare = true in your configuration and we’ll pull in only the parts of ActiveSupport explicitly needed for the parts of Rails that you use. You’ll still need to include the fancy parts if you want to use them – 3.days wont work out of the box with bare enabled.

ActionController

Another area that really needed an overhaul was ActionController. Previously, ActionController had a number of disparate elements all in one place. When we looked closely, we found that there were really three discrete components masquerading as one.

First, there was the dispatching functionality. This included the dispatcher itself, routing, middleware, and rack extensions. Second there was generic controller code that was meant to be reused elsewhere, and was in fact reused in ActionMailer. Finally, there was the subset of controller code that brought those two concerns together: code that handled requests and responses through a controller architecture.

In Rails 3, each of those components has been separated out. The dispatcher functionality has been moved into ActionDispatch, with the code inside tightened up and really made a conceptual component. The parts of ActionController that were meant to be reused by non-HTTP controllers was moved into a new component called AbstractController, which both ActionController and ActionMailer inherit from.

Finally, ActionController itself has gotten a significant overhaul. Essentially, we’ve isolated every standalone component, and made it possible to start with a stripped-down controller and pull in just the components you want. Our old friend ActionController::Base simply starts with that same stripped-down controller and pulls everything in. For instance, take a look at the beginning of the new version of that class:

module ActionController
  class Base < Metal
    abstract!

    include AbstractController::Callbacks
    include AbstractController::Logger

    include ActionController::Helpers
    include ActionController::HideActions
    include ActionController::UrlFor
    include ActionController::Redirecting
    include ActionController::Rendering
    include ActionController::Renderers::All
    include ActionController::Layouts
    include ActionController::ConditionalGet
    include ActionController::RackDelegation
    include ActionController::Logger
    include ActionController::Benchmarking
    include ActionController::Configuration

All we’re doing here is pulling in every available module, so the default experience of Rails is the same as before. However, the real power of what we’ve done here is the same as what we’ve done in ActiveSupport: every module declares its dependencies on other modules, so you can pull in Rendering, for instance, without having to wonder what other modules need to be included and in what order.

The following is a perfectly valid controller in Rails 3:

class FasterController < ActionController::Metal
  abstract!

  # Rendering would be pulled in by layouts, but I include
  # it here for clarity
  include ActionController::Rendering
  include ActionController::Layouts

  append_view_path Rails.root.join("app/views")
end

class AwesomeController < FasterController
  def index
    render "so_speedy"
  end
end

And then, in your routes, it would be perfectly valid to do:

MyApp.routes.draw do
  match "/must_be_fast", :to => "awesome#index"
end

Essentially, ActionController::Base has become just one way to express your controllers. Think of it like Rails Classic, with the ability to roll your own if you’re not so into that taste. It’s really easy to mix and match too: if you wanted to pull in before_filter functionality to FasterController, we could simply include AbstractController::Callbacks.

Note that without doing anything else, including those modules pulled in AbstractController::Rendering (the subset of rendering functionality shared with ActionMailer), AbstractController::Layouts, and ActiveSupport::Callbacks.

This makes it really possible to trivially pull in just the specific functionality you need in performance-sensitive cases without having to use an entirely different API. If you need additional functionality, you can easily just pull in additional modules or eventually upgrade to the full ActionController::Base without needing to rip anything apart along the way.

This, in fact, is a core idea of Rails 3: there are no monolithic components, only modules that work seamlessly together in a great package of defaults. This allows people to continue using Rails as they have used it successfully in previous versions, but really leverage the codebase for alternative uses. No more functionality locked away in non-reusable forms.

One nice immediate benefit of all of this is that ActionMailer gets all of the functionality of ActionController in a clean, intentional way. Everything from layouts and helpers to filters is using the identical code that ActionController uses, so ActionMailer can never again drift away from the functionality of ActionController (as ActionController itself evolves).

Middleware gets a helping hand too. ActionController::Middleware, which is middleware with all of the powers of ActionController, allows you to pull in whatever ActionController features you want (like Rendering, ConditionalGet, robust Request and Response objects, and more) as needed. Here’s an example:

# The long way
class AddMyName < ActionController::Middleware
  def call(env)
    status, headers, body = @app.call(env)
    headers["X-Author"] = "Yehuda Katz"
    headers["Content-Type"] = "application/xml"

    etag = env["If-None-Match"]
    key = ActiveSupport::Cache.expand_cache_key(body + "Yehuda Katz")
    headers["ETag"] = %["#{Digest::MD5.hexdigest(key)}"]
    if headers["ETag"] == etag
      headers["Cache-Control" = "public"]
      return [304, headers, [" "]]
    end

    return status, headers, body
  end
end
# Using extra Rack helpers
class AddMyName < ActionController::Middleware
  include ActionController::RackDelegation

  def call(env)
    self.status, self.headers, self.response_body = @app.call(env)

    headers["X-Author"] = "Yehuda Katz"

    # but you can do more nice stuff now
    self.content_type = Mime::XML # delegates to the response
    response.etag = "#{response.body}Yehuda Katz"
    response.cache_control[:public] = true

    self.status, self.response_body = 304, nil if request.fresh?(response)

    response.to_a
  end
end
# Using ConditionalGet helpers
class AddMyName < ActionController::Middleware
  # pulls in RackDelegation
  include ActionController::ConditionalGet

  def call(env)
    self.status, self.headers, self.response_body = @app.call(env)

    headers["X-Author"] = "Yehuda Katz"

    self.content_type = Mime::XML
    fresh_when :etag => "#{response.body}Yehuda Katz", :public => true

    response.to_a
  end
end

In all, I really think we’ve delivered on our promise to bring significant modularity improvements to Rails (and then some). In fact, I think the level of success that we’ve had with this version exceeds most people’s expectations of a year ago, and is solidly in golden unicorn territory. Enjoy!

Tomorrow, I’ll talk about bringing performance improvements to Rails 3. Hopefully it won’t go by too fast. :)


more »

RubyURL goes GOP... »

Created at: 17.12.2009 07:08, source: Robby on Rails, tagged: RubyURL Ruby on Rails programming RubyURL gop zombieurl

Will refrain from any political commentary, but was notified by some friends that the GOP was using the source code for RubyURL for their new URL shortening site (gop.am).

To celebrate, I decided to daisy chain a few rubyurl-based sites together and came up with:

Enjoy!

As always, you can fork/clone here


more »

Your Pages Will Load Faster with Rails! »

Created at: 15.12.2009 20:21, source: Engine Yard Blog, tagged: Technology GZip javascript Ruby on Rails YSlow

This article was originally included in the October issue of the Engine Yard Newsletter. To read more posts like this one, subscribe to the Engine Yard Newsletter.

In Inside Rails, Yehuda Katz, Rails expert and core team member, and Carl Lerche, Rails expert and full-time contributor, present expert advice and insight on the Rails platform and Rails development.


Server-side programmers tend to spend a lot of time tuning their server-side code. Studies show, however, that 90 percent of the user’s perceived performance is on the client-side. The YSlow recommendations are the gold standard for client-side performance, providing a list of things web developers can do both on the server-side and the client-side to improve performance. If you use Rails, a large number of these recommendations are baked into the framework.

These tips are not extremely difficult to implement yourself with another framework, but Rails and Engine Yard believe in making your websites fast by default: you shouldn’t need to understand all the minutiae in order to get a snappy application.

Use Far-Future Expires

YSlow recommends using an Expires header set far into the future. This means that browsers don’t need to ask for your images, JavaScripts, or stylesheets again after the first request. However, this introduces an additional problem: what happens if you (inevitably) change these files? Won’t the browser be stuck with the old file forever?

The solution is to include a last modified timestamp with your assets (something like <img src="/images/myasset.png?84392578943" alt="" />). When the file is modified, you update the timestamp, and the browser will know to ask for the file again.

When you use Rails, this timestamping is the default behavior; all you need to do is set up your Nginx or Apache config to serve with far future headers and you’re ready to go. And if you use Engine Yard, we set up those headers for you.

GZip Components

YSlow recommends GZipping JavaScript, CSS, and other textual assets. This reduces their file size over the wire by approximately 70%. This can be set up using your Apache or Nginx config. If you use Engine Yard, your assets are gzipped by default.

Split Components Across Domains

Some older browsers (*cough* IE *cough*) will only download two assets from a host at a time. This means that if you have two JavaScript files, two CSS files, and 10 images, these assets will come down two at a time, even though the user’s connection is fast enough to download them in parallel. The solution to this problem is to split your assets up over multiple hosts (assets0.yourapp.com, assets1.yourapp.com, and so on).

When using server-side code you wrote yourself, or using a traditional server-side framework, you’d be forced to go through all of the URLs you generated and update them to use an asset host helper. With Rails, you can simply add a single line to your configuration and all of your generated URLs will start using the asset hosts you specified:

config.action_controller.asset_host = "assets%d.yourapp.com"

Of course, you’ll need to set up a CNAME entry in your DNS to point the new virtual domains at the same host, but that should be trivial.

This also single-handedly resolves another YSlow recommendation: “Use Cookie-free Domains for Components.” If your assets and application are on the same domain, the browser and server will pass cookies back and forth (up to 4k worth) for each asset request. By using asset hosts for your assets, you get the side benefit of cookie-free domains for your assets.

When comparing frameworks, it’s tempting to look at something like “Etag Support” as a feature and simply check it off. Looking under the surface, however, there are complex considerations that are begging to be abstracted away from you. Why should you have to know what the header name in the request is called (If-None-Match) or how to generate a reliable unique key for an object?

Rails makes working with these ideas drop-dead simple, so you won’t have to stress about following web best practices; when using Rails, you’ll be doing the right thing and hardly know it. Stay tuned for a follow up post on more of the ways Rails makes fast page loading a breeze.


more »

Sending email: Controllers versus Models »

Created at: 16.11.2009 17:33, source: Robby on Rails, tagged: Ruby on Rails programming development rubyonrails actionmailer models controllers patterns

While reviewing some code recently, I came across controller code that resembled the following.

if @customer.save
  CustomerMailer.deliver_welcome_message(@customer)
  flash[:message] = "Your account has been successfully created. We've sent you a welcome letter with..."
  redirect_to dashboard_path
else
  ...
end

Fairly typical Rails code. Nothing alarming here, but I wanted to evaluate the call to the mailer in this scenario. When it comes to sending emails from your application, you can choose to do it from the controller as in the example above or in your models. Our team prefers to do this from our model via a callback as we are considering this to be part of our business logic.

Each time a customer is created, we want to send them an email. This can be moved into the model and resembled something like the following..

after_create :send_welcome_message #, other callbacks..

def send_welcome_message
  CustomerMailer.deliver_welcome_message(self)
end

There are a few benefits to doing it this way.

  1. We can test that this is being triggered within our model specs instead of our controller specs. (we prefer to spend more of our time working within models than controllers)
  2. We remove the dependency that all requests must be processed through our controllers.
    • Example: We may one day create rake tasks that data and want these emails to still be sent out. (We’ve had to do this a few times)

I definitely don’t think doing this via controllers is a bad idea, I just lean towards keeping controllers as dumbed down as possible. This allows us to have less controller code that is focused on passing data to/from models and letting our models do the heavy lifting.

UPDATE: DHH was kind enough to post a more detailed response on his blog.


more »