Deprecation of :selected option

yoprst edited this page Mar 14, 2014 · 9 revisions

In the Formtastic 0.9.8 gem, there is a deprecation warning about :selected/:default/:checked values, this wiki page is being created in advance so we have somewhere to link to and point people to upon release.

Where we started

Rails does a really bad job of the :selected option in its helpers. In most cases, using a :selected option will override the value. If you’re using the same form partial or view for creating and editing your models, you’ll find that’s a pretty bad thing. There is at least one helper in which the :selected option behaves more like a default, only applying this selection if the model doesn’t already have a value.

We think the latter default behaviour is much more ideal, so quite a bit of work was done to apply this, starting with a few hits-and-misses on the date and time inputs in the 0.9.7 gem (which has a bug), and then we stormed through every selectable input and try to apply this logic as a new :default option, replacing and fixing the behaviour of :selected and :checked.

Where we got stuck

The issue we ran into is related to the logic of when to use the default value supplied by the Formtastic form DSL, and when to use the model’s existing value for the attribute.

The ideal trigger to show a default value is if the attribute is nil, since an empty string (or an empty array of child objects), whilst empty, can still be a valid value (it’s ok for a Post’s description to be an empty string, it’s ok for a Post to have no tags). So, the trigger for using a default is if the object’s attribute is nil, empty isn’t enough.

Here’s the problem. has_many and has_and_belongs_to_many associations are never nil. An array is always returned, so there’s no way to discern if the association is intentionally empty (don’t apply the default) or not filled in yet (apply the default).

What we tried

We tried to use the default only of the object is a new_record?, but this would mean that the default form value would trump any previous selections on an unsaved record between requests (like, say, an object with some validation errors). No good.

What we won’t do

It’s really important that the Formtastic DSL and behaviour is consistent and predictable. So, while this problem only exists for some inputs and associations, we’re not interested in having options that behave quite differently depending on the input type or association type.

What we are doing

Right now, we don’t have a solution, just a problem. There’s a pretty sucky :selected implementation in 0.9.7, and there’s no candidate to replace it. This issue has paralysed and delayed the 0.9.8 gem a lot.

So, we’re deprecating the :selected and :checked options in 0.9.8. They’ll be removed from the 1.0 release, unless we come up with a decent solution between now and then.

Maybe we’re missing something cool in ActiveRecord. Maybe you have an insane solution. Please join the Formtastic Google group and get involved.

What to do instead

There’s two options. Either use an after_initialize block in your model, or set-up the default values just after you instantiate your object in the controller. Examples:

class PostsController < ApplicationController
  def new
    @post =
    @post.title = "Untitled" # set a default title
class Post < ActiveRecord::Base
  after_initialize :set_default_title
  def set_default_title
    self.title ||= "Untitled"

And you can still mix ERB and regular Rails helpers in with Formtastic helpers:

  %label{:for => "banner_entity_type"} Associated with
  = :entity_type, options_for_select(["Page", "Organization", "Promotion"], @banner.entity_type)