Posts tagged "rails"

We have been having some projects lately that needed a lot of admin CRUDs and pages showing a list of attributes, and we were getting bored of copy and paste code like this in our show pages, for every single attribute:

<p>
  <strong class="label">Name</strong><br />
  <%= @person.name %>
</p>

We had already created some helper to do the work for us, but having this helper being copied from one project to another wasn’t that DRY. That’s when we decided to create ShowFor.

ShowFor is a DSL to help you showing a list of attributes, with I18n, perfect for show pages in CRUD interfaces. It allows you to replace code/html duplication in your views using a nice syntax. Let’s see what we can do.

Attributes

Let’s imagine we have a Person model, which has first_name, last_name, age, photo, and confirmed attributes. The following lines show a list of values for a specific person:

<% show_for @person do |p| %>
  <%= p.attribute :first_name %>
  <%= p.attribute :last_name %>
  <%= p.attribute :confirmed? %>
  <%= p.attribute :created_at, :format => :short %>
  <%= p.attribute :age, :if_blank => "No age" %>
 
  <% p.attribute :photo do %>
    <%= image_tag(@person.photo_url) %>
  <% end %>
<% end %>

Here is an example output you will get:

<div class="show_for person" id="person_1">
  <p class="wrapper person_first_name"><strong class="label">First name</strong><br />Carlos</p>
  <p class="wrapper person_last_name"><strong class="label">Last name</strong><br />Antonio</p>
  <p class="wrapper person_confirmed"><strong class="label">Confirmed?</strong><br />Yes</p>
  <p class="wrapper person_created_at"><strong class="label">Created at</strong><br />08 Mar 11:30</p>
  <p class="wrapper person_age"><strong class="label">Age</strong><br />24</p>
  <p class="wrapper person_photo"><strong class="label">Photo</strong><br />
    <img alt="Rails" src="/images/rails.png?1268047643" />
  </p>
</div>

As you can see, you are going to get a default html markup, with classes and ids to help you design with CSS. And if you noticed, we are using extra options in some attributes, lets take a look at some of them:

  • :format lets you pass any format that will be used together with i18n, for date/time attributes only, as you would use with the l helper.
  • :if_blank specifies what to show if the attribute is blank. It may have a default value from i18n.
  • do...end: using blocks you can handle the content for that specific attribute by yourself, as we have done in this example for the photo attribute.

Boolean attributes, as our :confirmed, also have a default for true and false values, and can be configured through i18n. If you want to say “Yup” and “Nope” instead of “Yes” and “No” respectively, just change your i18n file. You can also pass a :escape option to not escape the value (true by default).

Associations

ShowFor also works with associations. For instance, we can easily add that a Person belongs to a City with a name attribute and that it has and belongs to many Tags. To handle the former, we can do:

<%= p.association :city %>

ShowFor will guess the right attribute to show by looking into all possibilities configured in ShowFor.association_methods and in this case choosing :name. But of course, you can change it as you need, on-the-fly:

<%= p.association :city, :using => :full_name %>
<%= p.attribute :full_name, :in => :city %>

Both calls above will have the same output, just choose the one which suits you better.

Handling collections is easy as belongs_to associations. You can just pass the association to ShowFor and it will know whether it’s a collection or not, generating a list of elements using ul and li tags.

<%= p.association :tags %>

However, if you want to render the collection inline, you can use :to_sentence or :join as options:

<%= p.association :tags, :to_sentence => true %>
<%= p.association :tags, :join => ',' %>

It’s also possible to pass a block to the collection. ShowFor will create the wrapper tag (ul by default in this case) and will yield each element in the collection for you to handle it:

<% a.association :tags do |tag| %>
  <li><%= link_to tag.name, tag %></li>
<% end %>

Labels

You may have noticed ShowFor has a default label using the strong html tag. It also exposes you this as a helper, so you can use it whenever you wish:

  <%= p.label :first_name %>
  <%= p.label :age, :id => 'person_age' %>
 
  <strong class="label">First name</strong>
  <strong class="label" id="person_age">Age</strong>

Installation

ShowFor is already compatible with Rails 3, at the time of this writing in version 0.2.0. You can just follow the instructions in the README to get it installed.

If you are using Rails 2.3.x, take a look at the 0.1 branch, and follow the installations in the README for this branch to get it up and running.

Please don’t forget to run the generator and take a look at the initializer, it will allows you configure several parts of ShowFor.

script/generate show_for_install

Closing

ShowFor helps you to show your objects easily with a default html markup, and can be totally configured to suit your needs. It has been helping us in every project, and we hope it may help you too. If you have any doubt, please take a look at the README, there are a lot of examples and documentation there.

And what about you? Do you have any helper you use every single day that might be transformed in a plugin/gem? Do not hesitate on doing this, we would be glad to see your work.

Enjoy!

RailsMetrics is a new Rails engine which stores everything that is happening inside your application in the database, so you can profile each request, besides creating charts, statistics and extract useful information.

I’ve been working on it for the last couple months in parallel with ActiveSupport::Notifications, which is the foundation for RailsMetrics, and it was open sourced today by Engine Yard!

It was a challenging project due to its threaded nature and I will share a couple things I learned during the process in this blog later. For now, you can watch the screencast below to see what it does and how to install it:

Rails Metrics Screencast – Feb/2010 from PlataformaTec on Vimeo.

As said in the video, getting it released is just the first step and now it’s your turn to fork and improve it by providing a better layout, creating new reports, charts, etc!

In case you are interested here are some screenshots that I tweeted earlier: http://twitpic.com/13e7fn/full and http://twitpic.com/13e7h2/full.

The javascript novell

A week ago I asked what people uses to create charts in Rails so I could evaluate what would be the best library to use in RailsMetrics. There were three types of libraries: server side ones, flash and javascript. Since I don’t want to depend on having neither RMagick nor Flash installed on the developer machine, I chose the javascript kind.

After some research I ended up with three libraries: g.raphael, flot and jqplot.

For RailsMetrics, I chose to use g.raphael since I can easily manipulate the objects it creates and it is the one which looks better (at least imho ;) ). However it has poor documentation and the default charts have poor customization options compared to the other two libraries, so you end up tweaking the chart by hand (which was fine in my experience).

I’m waiting for your pull requests, enjoy!

Today we are celebrating Devise‘s birthday. But wait, if you have started watching Devise since the beginning you may be asking: has Devise already completed one year of life? Nope. Today we are completing exactly 4 months since Devise was released at Rails Summit Latin America 2009. And we are very proud and glad to say that we have just reached version 1.0! Yeah! Let’s celebrate and talk a bit about history.

The beginning

We decided to build Devise based on some requirements we had in a project last year. The majority of our projects usually require an admin interface to configure the application with some CRUD information. And in this specific project, we were needing two different roles in the same application, the admin itself with all its powers to manage the application, and the end users that should be signed in to do some stuff inside the application. Usually only one model would be required in this situation, with some “type” column or flag to determine if the user is an admin or not, right? Okay, but we didn’t like this approach that much. So we started looking at some of the possibilities:

  • Authlogic: a really great piece of code and functionality, but a bit messy by handling the session in a model. It also only handles the model part.
  • Clearance: full stack, Rails Engine, extra modules, everything we needed. However, packaged with a User model and without the ability to customize it.

Okay, we could pick one of these and with a bit of extra work we would achieve our requirements. But would we need to do it every time this situation happens? We said no. It’s not DRY enough. And we like DRY. So Devise was born.

The main objective of the first Devise version was to get up and running the entire sign in process, including password recovery and confirmation stuff. And everything should work with different roles, which mean you could easily plug and play an Admin, User, Account, or whichever role you needed, in your application, without much effort. And we had a deadline: Rails Summit. It took almost 1 month of work before Rails Summit. I still remember the days before the event, we putting a lot of effort to have Devise up and running, and the README being written during the event. So, we were ready there and presenting Devise to the world.

How it works

Devise was born with the intuit of handling different roles without effort, automatically, and it is achieved with Rails Engines. In addition, Devise is build in top of Warden, a great rack authentication framework. It allowed us to be flexible enough and add different strategies, hooks, and modules easily. In short, Devise:

  • Is Rack based;
  • Is a complete MVC solution based on Rails Engines;
  • Allows you to have multiple roles (or models/scopes) signed in at the same time;
  • Is based on a modularity concept: use just what you really need.

The road so far

Devise has started with the basic modules needed for that specific application:

  • Authenticatable: responsible for signing users in through a basic login form, handling password validation and authentication.
  • Confirmable: manages confirming users account.
  • Recoverable: handles password recovery.
  • Validatable: basic email and password validation.

Okay, everything we needed were there. Everything else was in a wish list, nicely called TODO. And we decided from the beginning to not add features to Devise until us or somebody else really needed them. But people asked, people needed new features. And they were always there to help, to fork and fix a bug, to comment. We started soon to add new features, the first was:

  • Rememberable: handles signing users in automatically from cookies.

After people were asking for easier ways to create their migrations, so we introduced a new module with Devise 0.2:

  • Migratable: hooks into ActiveRecord migrations to add helper methods for creating Devise colums. So you can do stuff like t.authenticatable, t.confirmable and so on.

To help people getting up and running faster, we created some generators. Now they are:

  • script/generate devise_install: create devise initializer file to enable some configs and copy default locale file.
  • script/generate devise MyModel: create a model with setup for Devise, routes and migration.
  • script/generate devise_views: copy all Devise views to your app/views folder, so you can change it as needed.

Devise 0.3 and 0.4 came soon after, with a lot of bug fixes in generators, I18n, initialization, some deprecations and a bunch of code refactored.

Contributions from community were coming more and more. The first big contribution came with the addition of encryptors. Nowadays Devise supports encrypting passwords with SHA1, SHA512, and BCrypt. It has also support for using the same encryptors as Authlogic, Clearance and Restful Authentication, to help you migrating from these solutions.

At this point we thought: okay, that should be enough. It wasn’t. People needed different ORMs, other than ActiveRecord. So we introduced support to MongoMapper and then we were reaching Devise 0.5.

We were receiving a lot of issues with functional tests, so we introduced some test helpers to help people with the sign in/out process in this kind of tests called Devise::TestHelper.

As applications grow, more roles may be needed. So we created the possibility to scope your views for each role/scope in your application. This way your user can have a different sign in view than the admin, for example. Reaching Devise 0.6, a lot of improvements on routes and DataMapper support were added.

We were full of nice ideas to add new features, and our TODO was bigger than we like. So we came up with:

  • Timeoutable: verify each request to timeout the user session after a certain period of inactivity, asking for credentials again.
  • Trackable: records how many times each user has signed in, last timestamps and ips.

Also the loading process and ORM support received a lot of work before launching Devise 0.7.

For Devise 0.8 we looked at tests for MongoMapper and the code got a great review. Also some work was done to get Devise up and running with latest version of Warden and its new features, such as serializers. We also extracted a new base module from Confirmable:

  • Activatable: allow setting up extra activation methods for your models.

We were receiving a lot of feedback from the community, and then we merged a cool new feature:

  • Lockable: lock accounts based on a number of invalid sign in attempts.

Following the same pattern from Rails in this commit we moved flash messages to :notice and :alert, and released Devise 0.9. Step by step the 1.0 version was coming.

What is new

Devise 1.0 introduces a lot of cool features. The community seems to be really appreciating Devise, and we’ve received another great contribution:

  • Token Authenticatable: validates authenticity of a user while signing in using an authentication token (also known as “single access token”).

In addition, we created the two most requested features for Devise:

  • Registerable: handles sign up users through a registration process, and also editing/updating user info and deleting user account.
  • HTTP Authenticatable: http basic authentication.

We also added the possibility to use Migratable while editing a table using change_table, among other fixes.

What comes next

We are preparing a new release of Devise fully compatible with Rails 3. It means Devise has now closed its development for new features in Rails 2.x. We are still going to maintain a 1.0 branch in github for bug fixes to keep everything up and running.

In the end

We would like to say thank you to everyone who has helped us achieve 1.0 version and who is using Devise, testing, creating issues, and giving all this feedback.

Also, for those who were at Rails Summit last year, we proposed something: get the biggest number of watchers on github as fast as possible! When we presented Devise, there were 7 watchers, and if I am right we were 4 of them. At the time of this writing we have 762 watchers. Yeah! I think I can take the risk and say we accomplished it. Thanks!

Let’s celebrate Devise 1.0, and look forward to see Devise and Rails 3. Enjoy!

Happy birthday Devise!

As we already know, in Rails 3 all dependencies will be bundled. This means you will be able to use latest I18n version which includes several improvements by itself.

Besides that, a couple things changed on Rails 3 I18n, some features were added and others were deprecated. This post is a quick walkthrough it:

1) Error messages defaults

With the addition of ActiveModel, it’s easy to add I18n behavior to any object by simply including ActiveModel::Translation and ActiveModel::Validations. As side effect, if we followed the same translation pattern as in Rails 2.3, each ORM would have to specify its default error messages at #{ORM.name}.errors.messages. This means that if you are using two ORMs in your app, you would have to translate the same messages twice.

To handle this situation, error messages now has errors.attributes and errors.messages as fallbacks in case a message cannot be found for an specific ORM. Notice that this also allows you to customize a message for an specific attribute used by models in different ORMs. So if you have several models with title attribute, you can customize the blank message for them all by simply placing it at errors.attributes.title.blank.

2) Attributes default

In the same line as above, you can now specify default attributes across different models and ORMs as well. For example, if you are exposing created_at and updated_at in your views, until Rails 2.3 you needed to specify the same translation for each model. In Rails 3, you can simply do:

en:
  attributes:
    created_at: "Created at"
    updated_at: "Updated at"

3) f.submit

f.submit in forms now can be called without arguments and it will inspect the form object to set the proper label. Imagine the following form:

<% form_for @post do |f| %>
  <%= f.submit %>
<% end %>

If @post is a new record, it will use “Create Post” as submit button label, otherwise, it uses “Update Post”. You can customize those labels with I18n under the following keys:

en:
  helpers:
    submit:
      create: "Create a {{model}}"
      update: "Confirm changes to {{model}}"

Nonetheless, it also searches for keys under the object name key as well:

en:
  helpers:
    submit:
      post:
        create: "Add {{model}}"

4) Labels with I18n

Labels were also updated to use I18n. Imagine the following form:

<% form_for @post do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <%= f.submit %>
<% end %>

It will search for a label value at helpers.label.post.title, falling back to the value returned by Post.human_attribute_name(:title). This is useful in case you want more personalized labels instead of just “Title”.

5) Deprecation

Besides those improvements, I18n has two deprecations: the first is the key support.select should now be helpers.select and the other is that AV error messages are now agnostic, so activerecord.errors.template should now be errors.template.

That’s all, enjoy!

This weekend during Rails Bugmash I stumbled across some nice posts about Rails 3 generators which motivated me to share them and add some comments!

First, David Trasbo wrote a nice guide about how to make your first Rails 3 generator, it covers up all the basic steps including setting it up in a gem. He also puts the deserved attention into Thor::Actions, which contains most helpers you need in a generator, like copy_file, template, create_file, empty_directory and so on.

On another post, Ben Scofield talks about apply method, which is also in Thor::Actions, and how to use it to dry your application templates.

Wait… so Thor::Actions is used both in generators and in Rails application templates? Exactly, Rails’ new generators unifies both application templates and generators API into one. While Thor::Actions holds basic methods, all Rails specific methods like environment, rakefile, generator are in Rails::Generators::Actions. If you already wrote an application template, you will feel more at home when writing a Rails 3 generator.

Paul Barry talks how easy it’s to customize your scaffold to use Rspec, Haml and Factory Girl instead of Test::Unit, Erb and Fixtures. This all works because scaffold is just a meta generator which provides hooks for template engine, test framework, ORM and so forth. A good way to see the hooks system working is by running script/generate scaffold --help before and after Paul changes, so you can see exactly how generators options update depending on the configuration values you set. While I wrote Rspec generators used in the example, he implemented himself Haml and Factory Girl generators and they can all be used as example if you plan to build your own.

Finally, Zigzag Chen wrote about templates customization and how you can change your scaffold controller to use json instead of the xml format. New generators have source paths, so you can customize them simply by copying files to RAILS_ROOT/lib/templates.

Rails Bugmash was excellent to gather feedback and we also got some tickets on Lighthouse, mainly about how generators help can be improved for people starting with Rails. Many thanks to Rails Bridge and besides the posts linked above, there is a generator guide, which may help you get started and maybe write your own post as well. :)

A couple days ago DHH twitted that they were getting Basecamp running on Ruby on Rails 3.0.

This means Basecamp migrated from the first Rails release up to the edge one. So how come people say so frequently how hard is to update their applications from Rails 2.1 to Rails 2.2? And the answer is simple: plugins.

Every time you are adding a plugin to your application, you are inserting some hundreds or even thousands of lines of code in your application, without knowing what it does exactly. And sometimes this becomes technical debt, mostly noticeable when you have to update to a new Rails version. And why is that? Because a lot of plugins are monkey patching Rails, so whenever Rails changes its internal API between releases, the plugin breaks.

However, they are two simple actions you could do to improve your application maintainability, your ruby fu and also give a little back to the community.

The first one is easy: check the source code of the plugin you are installing. Does it needs to monkey patch Rails code? Or even worse, Ruby classes? If so, how much? If too much, turn it down. Search for simpler solutions or even start one from scratch with just what you need, it will take more time, but you will learn a lot through the process.

Another very compelling reason is that reading other people’s code is one of the best ways to learn. You will learn new things and probably see a few things which could be done better. And when it happens, write a patch!

Besides, whenever something is going wrong in your application, you will know better where to start searching and you will eventually help plugins authors to track bugs down. And, in the worst scenario, if you have to update the plugin after a Rails release on your own because the plugin creator is no longer interested, you will be more capable to do so.

Some people often choose plugin A because of features X, Y and Z. But whenever they have to add feature W, they are stuck, because the plugin code is a complete spaghetti. And all this time, they could have chosen plugin B, which just has feature X, but adding Y, Z and W would be quite easy. Reading the plugin’s source code is one way to ensure you are prioritizing code quality instead of features count.

And the second step, guess what, is easy too: run the plugin test suite. Really, it will take just a couple minutes. You definitely don’t want to use a plugin where the test suite fails (or which does not have a test suite at all). Imagine that for some reason you need to add features to a plugin, how you will ensure you did not break other thing while doing so? Or even worse, imagine you have to update the plugin for a new Rails release. How can you ensure the plugin works on 3.0 if you cannot even ensure it works on 2.3?!

Some already noted that I have patches applied in different plugins around GitHub. And this is the very reason: I check their code, send simple suggestions whenever it’s possible and most important of all, I choose well which plugins to use. So whenever I need to write a new feature because the application I’m working on needs it, I know it will be easy, since the plugin code is quite well written and test suite is green.

It’s really two small efforts, which gives everyone, including you, a lot back.