Most of the applications we create these days usually have an admin interface where an user with necessary privileges is able to manage the application content, respecting some business rules. Thus it is required that part of this content is easily manageable, which means the user needs to be able to add some formatting to the content. For us, it usually means that the user has to input HTML tags. And it also means that the user can do things that might break our application.
Luckily, Rails can help us since it has some helpers to sanitize and strip unwanted tags or attributes from the markup.
Strip links
If you just want to remove all links from the text you want to show, you can use the following method:
<%= strip_links 'Send e-mail to <a href="mailto:me@example.com">Me</a>.' %> Send e-mail to Me. |
Strip tags
This might be a bit famous: it removes all html tags from the given markup, using html-tokenizer:
<%= strip_tags '<p class="foo">Send e-mail to <a href="mailto:me@example.com">Me</a>.</p>' %> Send e-mail to Me. |
Sanitize
The sanitize helper encodes all html tags and strips all attributes that are not allowed, specially script tags.
<%= sanitize '<p id="bar" class="foo">foo bar <script>alert("I am a hacker!")</script> baz</p>' %> <p class="foo">foo bar baz</p> |
For instance here the script tag was removed, and also de id attribute from the paragraph tag.
Simple format
Together with sanitize we have the simple_format helper. Besides sanitizing the given content, it automatically converts one new line into a br tag, and two or more new lines into a p tag. Lets see how it works:
<%= simple_format "I am a text \n and I want to be formatted \n\n by <strong>simple_format</strong>", :class => 'foo' %> <p class="foo">I am a text <br /> and I want to be formatted </p> <p class="foo"> by <strong>simple_format</strong></p> |
So I want to change this stuff, and now, what happens?
Rails gives you the ability to configure most of what is allowed and what is not when sanitizing content. Lets see the available options:
- sanitized_uri_attributes
- sanitized_bad_tags
- sanitized_allowed_tags
- sanitized_allowed_attributes
- sanitized_allowed_css_properties
- sanitized_allowed_css_keywords
- sanitized_shorthand_css_properties
- sanitized_allowed_protocols
I believe these configs are pretty straightforward, but in case you have any doubt, check the docs in the source code. You can change any of these configs in your application file:
class Application < Rails::Application config.action_view.sanitized_allowed_tags = %w(table tr th td thead tbody tfoot) config.action_view.sanitized_allowed_protocols = %w(tel) end |
Wrapping up!
These simple helpers can make our life really easier when dealing with content coming from an admin interface, allowing specific tags and attributes to be shown, and doing the most they can to remove unwanted tags.
You can see more about them in the docs:
http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html
http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html
What about you, do you use some Rails helper that might be in the dark? We would love to bring it to the light side, share with us!
Tags: helpers, rails, sanitize
Posted in English | 2 Comments »
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!
Tags: form, gems, open source, plugins, rails, rails 3, simple_form
Posted in English | 46 Comments »
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:
- Update my RVM:
rvm update --head - Install ruby 1.9.2 head:
rvm install 1.9.2-head - Create a Rails 3 RVM gemset:
rvm --create use 1.9.2-head@rails3 - 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?
Tags: rails, rvm
Posted in English | 18 Comments »
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?
Tags: rails, recurrence
Posted in English | 2 Comments »
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!
Tags: authentication, devise, engine, plugins, rails, railscasts
Posted in English | 12 Comments »
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!
Tags: filters, form, rails, search
Posted in English | 2 Comments »

All
English only
Em português apenas