Update 08/13/2012
Since the new deprecation policy the composed_of removal was reverted. We are still discussing the future of this feature.
The reason
A few days ago we started a discussion about the removal of the composed_of method from Active Record. I started this discussion because when I was tagging every Rails issue according to its framework, I found some of them related to composed_of, that are not only hard to fix but would add more complexity for a feature that, in my opinion, is not adding any visible value to the framework.
In this presentation, Aaron Patterson talks about three types of features: Cosmetic, Refactoring, and Course Correction. Aaron defines cosmetic features as a feature that adds dubious value and unknown debt (I highly recommend that you watch the whole presentation to see more about these types of features). This is exactly what I think about composed_of. At this time this feature is adding more debt than value to the Rails code base and applications, so the Rails team have decided to remove this method.
The plan
The removal plan is simple, deprecate in 3.2 and remove in 4.0. This means that you need to stop using this feature and implement it in another way.
The Rails team have chosen this path because this feature can be implemented using plain ruby methods for getters and setters. You will see how in the next section.
Implementation
In the simplest case, when you have only one attribute and needs to instantiate an object with the value of this attribute, you can use the serialize feature with a custom serializer:
class MoneySerializer def dump(money) money.value end def load(value) Money.new(value) end end class Account < ActiveRecord::Base serialize :balance, MoneySerializer.new end |
To use it with multiple attributes you can do the following:
class Person < ActiveRecord::Base def address @address ||= Address.new(address_street, address_city) end def address=(address) self[:address_street] = address.street self[:address_city] = address.city @address = address end end |
Benefits for Rails developers
I already talked about what this removal can provide to Rails maintainers, but what benefits does it bring to Rails developers?
I think that the best advantages are:
- It is easier to test the composite objects;
- It is easier to understand the lazy methods;
- It is easier to customize it without resorting to options like
:converter,:constructorand:allow_nil.
Wrapping up
I strongly recommend that you read the whole discussion in the pull request. You will find more examples and additional information there.
Also, I want to thank @steveklabnik for working on this feature and the awesome work that he has been doing on the Rails Issues Team.
Finally, I want to invite you to help the Rails team to fix, test, and track issues. About half of the issues are related to the Active Record framework and we need to work on them. As a regular Rails contributor and Rails developer, I think there is still a lot we can do to improve the Rails code base, so join us.
Tags: activerecord, composed_of, rails 4
Posted in English | Comments Off
The Carnival is over in Brazil but we are still partying at Plataformatec by bringing you a complete new release of SimpleForm. This time is not a small bump though, it’s a shiny new version: SimpleForm 2.0, that comes with a bunch of new features and customizations, a new wrapper API to create custom input stacks and a great integration with Twitter Bootstrap.
Wrappers API
The new wrappers API is here in place of the old components option (besides some other *_tag and *_class configs), to add more flexibility to the way you build SimpleForm inputs. Here is an example of the default wrapper config that ships with SimpleForm when you run its install generator:
config.wrappers :default, :class => :input, :hint_class => :field_with_hint, :error_class => :field_with_errors do |b| ## Extensions enabled by default # Any of these extensions can be disabled for a # given input by passing: `f.input EXTENSION_NAME => false`. # You can make any of these extensions optional by # renaming `b.use` to `b.optional`. # Determines whether to use HTML5 (:email, :url, ...) # and required attributes b.use :html5 # Calculates placeholders automatically from I18n # You can also pass a string as f.input :placeholder => "Placeholder" b.use :placeholder ## Optional extensions # They are disabled unless you pass `f.input EXTENSION_NAME => :lookup` # to the input. If so, they will retrieve the values from the model # if any exists. If you want to enable the lookup for any of those # extensions by default, you can change `b.optional` to `b.use`. # Calculates maxlength from length validations for string inputs b.optional :maxlength # Calculates pattern from format validations for string inputs b.optional :pattern # Calculates min and max from length validations for numeric inputs b.optional :min_max # Calculates readonly automatically from readonly attributes b.optional :readonly ## Inputs b.use :label_input b.use :hint, :wrap_with => { :tag => :span, :class => :hint } b.use :error, :wrap_with => { :tag => :span, :class => :error } end |
Wrappers are used by the form builder to generate a complete input. You can remove any component from the wrapper, change the order or even add your own to the stack.
The :default wrapper is going to be used in all forms by default. You can also select which wrapper to use per form, by naming them:
# Given you added this wrapper in your SimpleForm initializer: config.wrappers :small do |b| b.use :placeholder b.use :label_input end # Uses the :small wrapper for all inputs in this form. simple_form_for @user, :wrapper => :small do |f| f.input :name end |
Or you can just pick a different wrapper in a specific input if you want:
# Uses the default wrapper for other inputs, and :small for :name. simple_form_for @user do |f| f.input :name, :wrapper => :small end |
You can see a more detailed description of the new wrappers API in the documentation.
Twitter Bootstrap
The second big change in SimpleForm 2.0 is out of the box Bootstrap integration. SimpleForm now ships with a generator option to initialize your application with a set of specific wrappers customized for Bootstrap. To get them, just run in your terminal, inside a Rails application (with SimpleForm already installed):
rails generate simple_form:install --bootstrap
This gives you the default SimpleForm initializer in config/initializers/simple_form.rb with some extra integration code added for Bootstrap. For example, here is the default wrapper:
config.wrappers :bootstrap, :tag => 'div', :class => 'control-group', :error_class => 'error' do |b| b.use :placeholder b.use :label b.wrapper :tag => 'div', :class => 'controls' do |ba| ba.use :input ba.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' } ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' } end end |
This wrapper is setup with the same structure that Bootstrap expects and is set to be the default wrapper in your application. This is the killer feature in SimpleForm 2.0: the Bootstrap integration is not inside SimpleForm but all in your application. This means that, if you want to move away or customize Bootstrap in the future, you don’t need to monkey patch SimpleForm, everything is in your app!
We’ve set up a live example application showing most of the SimpleForm inputs integrated with Twitter Bootstrap, make sure you check it out! The application code is on github.
Keep reading this blog post to find out the other changes and deprecations that gave SimpleForm all this extra flexibility, allowing it to be easily integrated with Twitter Bootstrap 2.0.
New configs
SimpleForm 2.0 comes with some new configs to ease its integration with Bootstrap and to make your daily work even more flexible:
default_wrapper: defines the default wrapper to be used when no one is given.button_class: defines a class to add for all buttons.boolean_style: change the way booleans (mainly check boxes and radio buttons) are shown::inline(the default) uses the same structure as before, checkbox + label;:nested(generated for new apps) puts the checkbox inside the label, as label > checkbox.collection_wrapper_class: class to add in all collections (check boxes / radio buttons), givencollection_wrapper_tagis set.item_wrapper_class: class to add to all items in a collection.generate_additional_classes_for: allows you to specify whether to generate the extra css classes for inputs, labels and wrappers. By default SimpleForm always generate all classes, such as input type and required info, to all of them. You can be more selective and tell SimpleForm to just add such classes to the input or wrapper, by changing this config.
Deprecations
In order to create the new wrappers API, we had to deprecate some configs and change some helpers, so here is a basic summary of what is being deprecated:
Configs
translate: By makingplaceholderandhintoptionaloptions in the wrappers API, you can already disable the automatic translation attempt that happens for these components.labels, on the other hand, are always used in forms, so we added a special config for them:translate_labels.html5: this config is now part of the wrappers API, withb.use :html5, so the config option has been deprecated.error_notification_id: in favor of usingerror_notification_classonly.wrapper_tag=, wrapper_class=, wrapper_error_class=, error_tag=, error_class=, hint_tag=, hint_class=, components=: all these were moved to the wrappers API structure, and are not required anymore.
Helpers
:radioinput type: In order to integrate with Bootstrap, we had to get rid of the:as => :radioand use:as => :radio_buttonsinstead. The former still works, but will give you a bunch of deprecation warnings. CSS class names changed accordingly as wellcollection_radio: has changed tocollection_radio_buttonsto follow the:as => :radio_buttonschange. Its label class has changed as well based on the helper name.
Wrapping up
SimpleForm 2.0 comes with a lot of new features, in special the new wrappers API, to make it flexible enough to allow you to customize inputs as much as possible in an easier way, and to bring you the integrated Bootstrap structure.
Make sure you check out the new SimpleForm README and also the CHANGELOG for a full list of changes. We’ve also created an special wiki page to help you Upgrading to SimpleForm 2.0.
If you find any trouble while migrating to 2.0, or any issue with Bootstrap integration, or any other issue, please let us know in the issues tracker. And if you have any questions, make sure to send them to the mailing list, there are a lot of people there to help you.
All our development team and an amazing number of contributors put a lot of effort into this new release and we hope you will enjoy it. SimpleForm 2.0 + Bootstrap: from us, for you, with love.
Thoughts about SimpleForm 2.0? Please let us know in the comments.
Tags: form, gems, open source, rails, simple_form, twitter bootstrap
Posted in English | 5 Comments »
I’m pleased to say that we released SimpleForm 1.4. Like the last version, this release had a lot of contributions from the community, closing bugs and adding some nice features. Here is a brief introduction to some of the new features:
Custom Form Builders
Now you can set a custom form builder that inherits from SimpleForm::FormBuilder:
class CustomBuilder < SimpleForm::FormBuilder def input(attribute_name, options={}, &block) options[:input_html].merge! :class => 'custom' super end end |
And use it straight in the simple_form_for helper, like the example below:
<%= simple_form_for(@user, :builder => CustomBuilder) do |f| %> <%= f.input :name %> <% end %> |
Custom Inputs
SimpleForm has many different inputs available in its source code. But, sometimes, depending on the business logic the application requires, we need to add new inputs to make our work easier. Before this version, you had to explicitly define your new input inside SimpleForm namespace for it to work. Furthermore, customizing existing SimpleForm inputs could only be achieved through monkey patching.
Inspired by a similar feature in the Formtastic gem, from now on you will be able to create new input types inside app/inputs folder in your application. The only restriction to create such inputs is that the class name must end with Input. See some examples:
# app/inputs/currency_input.rb class CurrencyInput < SimpleForm::Inputs::StringInput def input "$ #{super}".html_safe end end |
And the usage:
f.input :money, :as => :currency |
You can also redefine existing SimpleForm inputs by creating a new class with the same name. For instance, if you want to wrap date/time/datetime inputs in a div, you can do:
# app/inputs/date_time_input.rb class DateTimeInput < SimpleForm::Inputs::DateTimeInput def input "<div>#{super}</div>".html_safe end end |
HTML 5
SimpleForm allows you to add many HTML 5 features to your applications, like placeholders, inline browser validations and more. The problem is: most browsers are still experimenting some HTML 5 features, and people started having lots of troubles with the automatic browser validation.
For this reason, SimpleForm now has an option to easily disable such form validations. You have to add this line to your SimpleForm initializer:
config.browser_validations = false |
But, if HTML 5 is still not for you, you can disable all the HTML 5 stuff, by adding the configuration below to your initializer:
config.html5 = false |
Notice that this option does not disable the `placeholder` component, because we believe this option is very well supported currently in mostly browsers. If you don’t want to use it as well, just remove it from the `components` option in your initializer.
More Helpers
In this version we also add two new form helpers to SimpleForm: input_field and full_error.
The full_error helper shows errors in an attribute prepending its human name. This can be used when you want to show errors on hidden fields, for instance. You can see how it works in this example:
f.full_error :token #=> <span class="error">Token is invalid</span> |
The input_field helper renders only the input tag with all the facilities of SimpleForm’s input helper. It means no wrapper, error or hint will be rendered. A good example of using this helper is inside an input block:
<%= f.input :max_time, :as => :integer do %> <%= f.input_field :max_time, :as => :integer, :type => :range %> <%= content_tag :span, '1', :id => 'max_time_value' %> <% end %> |
It will render:
<div class="input integer required"> <label class="integer required for="model_max_time">Max time <abbr title="required">*</abbr></label> <input class="numeric integer required" id="model_max_time" name="model[max_time]" required="required" size="50" type="range" /> <span id="max_time_value">1</span> </div> |
Wrapping up
This version allows you to do more customizations in SimpleForm based on your applications needs. We encourage you to take a look at the CHANGELOG and also review the README to see what else is available and some more examples.
And please, check out SimpleForm contributors, we want to thank everyone who is helping us to improve SimpleForm.
Right now, we are working on Rails 3.1 compatibility for the next version. If you feel like helping us or just want to see a new feature, feel free to send us a pull request. And last, but not least, we look forward to know how SimpleForm is changing your life. Is it being helpful? How does it improve your applications? Don’t be shy, comments are welcome.
Tags: form, gems, html 5, open source, rails 3, simple_form
Posted in English | 2 Comments »

All
English only
Em português apenas