Skip to content

Using Mobility with Forms

Chris Salzberg edited this page Jun 3, 2017 · 13 revisions

A common use case involves translating content using a form (in Rails). Here we look at some issues with this use case and ways to solve them.

Fallbacks

If you define fallbacks on your model, by default you will see the fallback locale value of an attribute in the form if the value in the current locale is not available. Submitting the form will then save this fallback value, which is not generally what you would want. (See this issue for reference).

To solve this, you can pass a fallback option to the attribute reader to disable using fallbacks:

post.title(fallback: false)
#=> returns the actual value of the title, in the current locale, or nil if it is nil

In your form, you can set this as the default value for every translatable attribute:

<%= form_for @post do |f| %>

  ...
  <%= f.label :title %>:
  <%= f.text_field :title, value: @post.title(fallback: false) %><br />
  ...

  <%= f.submit %>
<% end %>

This may become cumbersome if you have many translated attributes and many forms. To make this default, use this form builder, which will automatically disable fallbacks on all translated attributes:

class FallbacksDisabledFormBuilder < ActionView::Helpers::FormBuilder
  %w[text_field text_area].each do |field_name|
    define_method field_name do |attribute, options={}|
      if @object.translated_attribute_names.include?(attribute)
        super(attribute, options.merge(value: @object.send(attribute, fallback: false)))
      else
        super(attribute, options)
      end
    end
  end
end

You can use the builder in your form with builder: FallbacksDisabledFormBuilder, like this:

<%= form_for @post, builder: FormBuilderWithFallbacksDisabled do |f| %>

  ...
  <%= f.label :title %>:
  <%= f.text_field :title %><br />
  ...

  <%= f.submit %>
<% end %>

For more on form builders, see the rails docs.