Posts tagged "rails"

Sometime ago we were working on a project together with a designer, and that specific application was full of forms, each one having a different layout, but most of them sharing the same features: inline errors, hints, specific label markup for required fields, etc. To start prototyping the application faster, we used the markup the designer created with similar forms, duplicating the code. But we don’t like code duplication, we weren’t feeling comfortable with it. So we decided to move on and create a tool to help us, that should be flexible enough to let us define the markup that fits better for each application, or even no extra markup at all. Here is SimpleForm!

SimpleForm inputs

From the README:

Forms made easy (for Rails)!

SimpleForm aims to be as flexible as possible while helping you with powerful components to create your forms. The basic goal of simple form is to not touch your way of defining the layout, letting you find the better design for your eyes. Good part of the DSL was inherited from Formtastic, which we are thankful for and should make you feel right at home.

As the README says, SimpleForm is a tool to help you build forms easily in Rails. Let’s see some examples:

<%= simple_form_for @user do |f| %>
  <%= f.input :username, :label => 'Your username please' %>
  <%= f.input :password, :hint => 'No special characters.' %>
  <%= f.input :remember_me, :as => :boolean %>
  <%= f.button :submit %>
<% end -%>

There are plenty of things going on here: we create a form using simple_form_for helper, then we use the :input method to create input elements based on column type. For instance, :username will create a default text input, while :password attribute will render an input type password. For the :username attribute, we are specifying a label manually. For :password, the label will be taken from I18n, and we are adding a hint message to the field. For :remember_me, we are explicitly saying to render it as a checkbox, using the :as => :boolean option (that is the default for boolean attributes). Also, there is a button helper that simply delegates to Rails helpers, in this case submit.

The output for a new @user would be:

<form action="/users" class="simple_form user" id="new_user" method="post">
  <div class="input string required">
    <label class="string required" for="user_username"><abbr title="required">*</abbr> Your username please</label>
    <input class="string required" id="user_username" maxlength="255" name="user[username]" size="50" type="text" />
  </div> 
  <div class="input password required">
    <label class="password required" for="user_password"><abbr title="required">*</abbr> Password</label>
    <input class="password required" id="user_password" name="user[password]" size="30" type="password" />
    <span class="hint">No special characters.</span>
  </div> 
  <div class="input boolean optional">
    <label class="boolean optional" for="user_remember_me"> Remember me</label>
    <input name="user[remember_me]" type="hidden" value="0" />
    <input class="boolean optional" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1" />
  </div> 
  <input id="user_submit" name="commit" type="submit" value="Create User" /> 
</form>

You may have noticed there is some additional css classes added to the markup, like string and required. They are added automatically by SimpleForm to help us style and plug some javascript in. There are specific css classes for each available input type. Also, pay some attention to the label: inside it there is an abbr tag with an asterisk (*) showing that the field is required. SimpleForm uses the new validations reflection API from Rails 3 to check if the attribute has the presence validator, and mark the field as required if so. And we are able to say that a field is required or disable the required mark, by passing the option :required => true|false.

Furthermore, there is the hint tag for the :password attribute that SimpleForm creates based on the :hint option we have defined. Also notice that the gem has automatically added a div wrapper to each input, with the same css classes. SimpleForm allows us to configure this wrapper as well, using for instance p instead of div. We are going to see more about configuration later.

SimpleForm is already prepared to generate some of the new HTML 5 input tags, such as email, url and number inputs:

<%= simple_form_for @user do |f| %>
  <%= f.input :website, :as => :url %>
  <%= f.input :email %>
  <%= f.input :age, :hint => "This defaults to 'number' input based on field type" %>
  <%= f.button :submit %>
<% end -%>

Based on the attribute name, SimpleForm will generate url or email input types, and we can always set a specific type with the :as option. Numeric attributes will always be rendered as input type number.

Working with associations

SimpleForm adds a custom and straightforward method to render select tags for associations, called association. For now, consider our User belongs to a Company, and has and belongs to many Roles. Let’s go straight to the example:

<%= simple_form_for @user do |f| %>
  <%= f.input :name %>
  <%= f.association :company %>
  <%= f.association :roles %>
  <%= f.button :submit %>
<% end -%>

It will detect the association type and render a select tag for choosing the company, listing all companies in the database, and another select for roles, with multiple option enabled.

SimpleForm also has some add-ons, letting us render associations as a collection of radios or check boxes. Using the same example:

  f.association :company, :as => :radio
  f.association :roles, :as => :check_boxes

Now we are rendering a collection of radios for choosing the Company, and another collection of check boxes for choosing Roles.

Configuration

SimpleForm lets us do some customizations by running its install generator:

rails generate simple_form:install

# Output
  create  config/initializers/simple_form.rb
  create  config/locales/simple_form.en.yml
  create  lib/templates/erb/scaffold/_form.html.erb

As we can see, running this generator will copy an initializer file, responsible for configuring SimpleForm; a locale file, to let us change some I18n messages; and a form template inside our lib dir. This template will be used instead of the default Rails scaffold form template, so it will create our form already using SimpleForm. Easy, right?

Let’s take a look at some configuration options:

  • components: defines the components used by the form builder. We can remove any of them, change the order, or add new ones. Defaults to [ :label, :input, :hint, :error ].
  • hint_tag: tag used for hints, defaults to span.
  • error_tag: tag used for errors, defaults to span.
  • wrapper_tag: tag used as wrapper to all inputs, defaults to div
  • label_text: determines how the label text should be generated altogether with the required text. It must be a lambda/proc that receives both label and required texts. Defaults to "required label".

There are a lot more options available in the initializer file, such as default input size and priority countries for generating country selects. Also, the locale file lets us determine the required text and mark, or even the entire required html tag.

Internationalization

SimpleForm is ready for I18n, supporting labels and hints. In addition, it lets us set different content for each action, new and edit. Here is an example locale file:

  en:
    simple_form:
      labels:
        user:
          username: 'User name'
          password: 'Password'
          edit:
            username: 'Change user name'
            password: 'Change password'
      hints:
        user:
          username: 'User name to sign in.'
          password: 'No special characters, please.'

Simple, right? If it does not find any specific translation using I18n for the label, it will fallback to human_attribute_name.

Here we go!

SimpleForm has much more to offer. We would like to invite you to take a better look at the examples and possibilities. Remember, SimpleForm aims to be flexible and powerful to help you easily build forms, without saying how you should create your markup.

Also, feel free to explore the source code and extend SimpleForm even further. Since it’s based on components, creating a new component which moves the current hints to inside the input (using javascript or the new placehoder attribute in HTML 5), should be easy!

It’s worth saying SimpleForm is Rails 3 compatible in the master branch. If you are using Rails 2.3.x, there is a v1.0 branch and version that you might want to take a look.

SimpleForm has been helping us a lot so far, we hope you enjoy it. Moreover, we would like to enjoy other tools that help your productivity day by day, please leave a comment and let us know, we would appreciate a lot!

I’ve been playing a lot with Rails 3 lately, it’s completely awesome! However, we don’t have any Rails 3 app in production at the moment, all projects that Plataforma has been doing for its clients so far are using Rails 2.3.5. Since I was already having fun with Rails 3, I thought I should also give ruby 1.9 a try. Ok, so how could I have Rails 2.3.5, Rails 3, ruby 1.8.7 and ruby 1.9 in my machine without going crazy? The answer is RVM (Ruby Version Manager)!

RVM is an awesome tool that gives you the power to have as many rubies in your machine as you want, and the best of all, all versions are isolated, no conflicts at all. In order to install it, follow the instructions inside RVM’s site. After that, I installed ruby 1.9.1 through RVM with rvm install 1.9, installed all the gems necesssary to play with Rails 3 (gem install rails --pre) and then, I could start to play.

I was playing with that configuration successfully until the moment I got a segmentation fault error. Other people got the same error too. Thankfully the problem didn’t last too long, this was one of these moments which I was very happy for having a Rails Core member in my team (@josevalim). He told me that Rails 3 doesn’t support ruby 1.9.1, actually, it’s supporting ruby 1.9.2! So, I needed to install a new ruby version, and install all Rails 3 gems again, damn it! But, I was fortunate enough for being using RVM.

In order to install Ruby 1.9.2-head and Rails 3 gems, all I needed to do was:

  1. Update my RVM: rvm update --head
  2. Install ruby 1.9.2 head: rvm install 1.9.2-head
  3. Create a Rails 3 RVM gemset: rvm --create use 1.9.2-head@rails3
  4. Copy my already installed Rails 3 gems to my new RVM gemset within my ruby 1.9.2: rvm gemset copy 1.9.1 1.9.2-head@rails3

That’s all! After that, I was back to the game! Man, RVM is awesome!!!

Be sure to have a look at a Wayne’s gist about how to install Rails 3 with RVM, and, check out RVM’s Gemsets feature, it’s very useful.

And you, do you have any tips about dealing with many versions of ruby and/or Rails, or about RVM?

We have been working in a project which deals with date events and we needed a recurrence feature in the application. An initial implementation could simply work with Rails ActiveSupport and use its Date helper methods, in order to shift by day, week, month and others.

>> Date.today
=> Thu, 15 Apr 2010
>> Date.today.next_month
=> Sat, 15 May 2010
>> Date.today.next_week
=> Mon, 19 Apr 2010
>> Date.today.next_week(:thursday)
=> Thu, 22 Apr 2010
>> Date.today.advance(:days => 4)
=> Mon, 19 Apr 2010

Very easy, right? But what if we now want events that occur every monday or sunday? Or events that happen at each two weeks? For each new case, we will need to add and deal with more and more logic.

Instead we have been using the Recurrence gem, created by Nando Vieira with some contributions by José Valim (yeah, our good fellow ;)). Recurrence works with ActiveSupport as its base for date calculation and provides a simple DSL to work with recurring events. Let me show a simple example:

# events every day, considering today as Apr 15th.
>> r = Recurrence.new(:starts => 2.days.ago, :every => :day, :until => Date.tomorrow)
>> r.events
=> [Tue, 13 Apr 2010, Wed, 14 Apr 2010, Thu, 15 Apr 2010, Fri, 16 Apr 2010]

If no :until is determined, it runs until year 2037 (maybe the end of world? No, it’s when the unix time 32-bit overflow…). You can check the Github repository and this blog post (in brazilian portuguese) to learn different use cases and examples for Recurrence.

Now I want to show you how we integrated it with our application. We have built an EventRecurrence class which deals internally with the recurrence logic.

# app/models/event_recurrence.rb
# It has :start_date, :every and :end_date as database columns
class EventRecurrence < ActiveRecord::Base
  def dates(options={})
    options = {:every => every, :starts => start_date, :until => end_date}.merge(options)
    options[:on] = case options[:every]
    when 'year'
      [options[:starts].month, options[:starts].day]
    when 'week'
      options[:starts].strftime('%A').downcase.to_sym
    when 'day', 'month'
      options[:starts].day
    end
    Recurrence.new(options).events
  end
end

Notice we need to setup the options hash for different cases (day, week, month and year) because the configuration options changes for each. Now, accessing all the recurring dates for one model is quite easy:

>> er = EventRecurrence.new(:start_date => Date.today, :every => :month, :end_date => 6.months.from_now)
>> er.dates
=> [Thu, 15 Apr 2010, Sat, 15 May 2010, Tue, 15 Jun 2010,
Thu, 15 Jul 2010, Sun, 15 Aug 2010, Wed, 15 Sep 2010, Fri, 15 Oct 2010]

Since EventRecurrence is a model, these options are saved in database and we can update or use them for querying freely. For instance, if we want to look for all dates in a given period, we just search for all EventRecurrences that are in the range and collect the dates returned by recurrence. Here you can see a raw implementation of this idea:

class EventRecurrence < ActiveRecord::Base
  # Retrieves a list of all dates for a period
  def self.dates_between(start_date, end_date)
    # Filtering EventRecurrence on the period using a between named scope
    recurrences = EventRecurrence.between(start_date, end_date)
 
    recurrences.inject([]) do |dates, recurrence|
      # Use the given dates instead of the ones in the DB
      dates.concat(recurrence.dates(:starts => start_date, :until => end_date))
    end
  end
end

This is just an initial post showing some ideas to get you going with recurring events. If you are interested, there is a lot of information related to this topic, like Recurring Event in Calendars, an article by Martin Fowler, and the iCal RFC2445 which includes calendar specifications.

And you, have some different solutions about recurring events to share with us?

Two months ago we were celebrating Devise’s birthday. We were not talking about its age, Devise had just 4 months of life, but we were happy to reach the 1.0 release.

Today we are celebrating again! We are very proud and glad to have Devise in its first Railscast! Ryan Bates has done a great job explaining how to get Devise up and running in a Rails 3 application, showing how to install Devise and choose the basic modules you want to use in your application.

We also made a promise to you: get Devise up and running for Rails 3. We keep walking this road, each Rails beta version released we are releasing a new compatible Devise version. For the time being, we have Devise 1.1.rc0, a release candidate version, compatible with Rails 3 beta 2.

We are looking forward to see the second part of Devise’s Railscast, about how to configure Devise to fit the needs of your application.

Give Devise a try. You can post your questions to the mailing list and, if you find any issue, please use the Github Issue Tracker. Don’t forget to post information about your environment (like Devise, Warden and Rails versions) including the stack trace if you are facing an error, to help us help you =). Enjoy!

Update: Railscasts just released the second part of Devise screencast, Customizing Devise, going through Devise configuration options. Check it out!

Rails is very friendly whenever you need to create forms to input data to your web app’s database. Things get a little different when you must have forms and you don’t want to save anything in the database. For that, you have to resort to other ways, maybe creating tableless models.

However, there are some simple cases that even creating a new class seems an overkill, such as forms for searching or filtering data in your app. In these cases, you just want a form that user can pick options and hit a button to see the results. When returning to the user, it is expected to have that form filled with the options the user had chosen before, but there is no simple, clean way to do that with plain old “form_tag”. Here is where our little tip comes in.

OpenStruct is a cool lib that comes with the Ruby Standard Library. “It is like a hash with a different way to access the data” says the documentation:

>> user = OpenStruct.new({:name => 'John', :last_name => 'Doe'})
=> #<OpenStruct name="John", last_name="Doe">
>> user.name
=> "John"
>> user.last_name
=> "Doe"
>> user.bla
=> nil

We can use it to fool our old friend “form_for” helper to think we’re dealing with normal AR objects, so we can create a method that wraps “form_for”, simple as this:

require 'ostruct'
module SearchFormHelper
  def search_form_for(object_name, options={}, &block)
    options[:html] = {:method => :get}.update(options[:html] || {})
    object = OpenStruct.new(params[object_name])
    form_for(object_name, object, options, &block)
  end
end

Inside the view, you will do the same way you do with AR models:

<% search_form_for :search do |f| %>
  <p>
    <%= f.label :start_at %>
    <%= f.date_select :start_at %>
  </p>
  <p>
    <%= f.label :end_at %>
    <%= f.date_select :end_at %>
  </p>
  <p>
    <%= f.submit 'Search' %>
  </p>
<% end %>

That’s pretty much it! If you’re filtering data, by a category for example, try checking the has_scope plugin, works like a charm in combination with this tip, but it is a matter for other post.

And you, reader, do you have any little tricks like this? If you don’t mind, share with us!

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!