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!
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
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
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
<%= 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
: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
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
- error_tag: tag used for errors, defaults to
- wrapper_tag: tag used as wrapper to all inputs, defaults to
- 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
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.
SimpleForm is ready for I18n, supporting
hints. In addition, it lets us set different content for each action,
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
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.
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!
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.
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!
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.
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:
:formatlets you pass any format that will be used together with i18n, for date/time attributes only, as you would use with the
:if_blankspecifies 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
Boolean attributes, as our
:confirmed, also have a default for
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).
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
<%= 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 %>
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>
Please don’t forget to run the generator and take a look at the initializer, it will allows you configure several parts of ShowFor.
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.
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.
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.confirmableand 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.
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.
What is new
- 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!
Happy birthday Devise!
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
empty_directory and so on.
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
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.
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.