Samuel Mullen

More than enough Arel

When ActiveRecord just isn’t enough

In Just Enough Arel, we explored a bit into how the Arel library transforms our Ruby code into SQL to be executed by the database. To do so, we discovered that Arel abstracts database tables and the fields therein as objects, which in turn receive messages not normally available in ActiveRecord queries. Wrapping up the article, we also looked at arguments for using Arel over falling back to SQL.

As alluded at the end of the previous article, Arel can do much more than merely provide a handful of comparison operators. In this post, we’ll look at how we can call native database functions, construct unions and intersects, and we’ll wrap things up by explicitly building joins with Arel.

Read more…

Just Enough Arel

Replacing hand-coded SQL with object oriented programming

If you were a web developer prior to ActiveRecord, you probably remember rolling your own SQL and being specific about which fields you retrieved, writing multiple queries to handle “upserts” (update or insert), and getting frustrated with how difficult it was to generate SQL dynamically.

Then Ruby on Rails came along with its ActiveRecord API, and all of that pain seemed to melt away into distant memory. Now we no longer have to worry about which fields to retrieve, “upserts” can be handled with a single method, and scopes allow us to be as dynamic as we want.

Unfortunately, ActiveRecord introduced new pains: the “WHERE” clause (i.e. the predicate) only allows connecting conditions with “AND”s, and the only comparisons allowed are “=” and “in”. To get around this, we often concede ActiveRecord’s shortcomings and revert back to raw SQL. But in Rails 3.0, we were introduced to another way.

Arel

The Arel relational algebra library is an abstract syntax tree (AST) manager and has the goals of “1) Simplif[ying] the generation of complex SQL queries; and 2) Adapt to various RDBMSes”. It’s the “engine” ActiveRecord uses to change method calls into actual SQL. To be clear, Arel only generates SQL, it doesn’t access the database and retrieve data.

With Arel, we are now capable of fully utilizing the power of SQL, without the mess of hand-coding it. ActiveRecord uses Arel to transform queries like this:

Post.joins(:comments).
  where(:published => true).
  where(:comments => {:flagged => true})

Into SQL like this:

SELECT "posts".*
  FROM "posts" INNER JOIN "comments" ON "posts"."id" = "comments"."post_id"
 WHERE "posts"."published" = true
   AND "comments"."flagged" = true

Read more…

Delegation patterns in Ruby

Reducing object bloat begins with doing less

[inlinetweet]In almost every project there are those objects which seemingly get involved in every aspect of the application.[/inlinetweet] These are the so-called “god objects”: they can do everything (omnipotent), they know everything (omniscient), and they are everywhere in the application (omnipresent). Most often these are objects which are at the intersections of business logic: User or Account, Project, and Order are all usual suspects.

One of the core tenants of object-oriented programming is that large problems are made up of many smaller problems, and as such, can be solved by providing solutions to those smaller problems in the form of objects. [inlinetweet]God objects violate this core tenet by trying to be one solution for too many problems.[/inlinetweet]

[inlinetweet]A typical example of a god object is the `User` model of many Rails applications.[/inlinetweet] Here, `User` might be responsible for user specific information as well as knowing about phone numbers, emails, profile information, preferences, and handling authentication. It’s too much and it results in `User` being coupled to every aspect of the application.

Although there are many tactics a developer can employ to limit the influence of these “god objects”, one of the simplest is just reassigning some of their responsibility, and using a delegation pattern may be the simplest way to do just that.

[inlinetweet]Let’s look at four different ways we can use delegation in Ruby.[/inlinetweet]

Read more…