Latest Comment by Ben ~ Thu Jan 28 on Git stash

form_assistant plugin updates

The changes made to my form_assistant plugin warrant a new post. They’re somewhat drastic when compared to how it worked originally.

General Usage

To use the form_assistant randomly in your application, take this approach:

1
2
3
<% form_assistant_for @project do |form| %>
  // typical form_for stuff
<% end %>

That’s the only thing you need to know. There’s no longer a separate helper for the inline errors, since the new version uses templates now.

If you’d like to make it the default in your application, take this approach:

1
ActionView::Base.default_form_builder = RPH::FormAssistant::FormBuilder

That would allow you to use form_for as you normally would.

Templates

The most notable change (I think) is the use of templates. Now, each rendered element has a corresponding template. The naming (by default) is the name of the helper. For example:

1
2
3
4
5
# renders app/views/forms/_text_field.html.erb
<%= form.text_field :name %>

# renders app/views/forms/_text_area.html.erb
<%= form.text_area :description %>

And so on. Of course, you can override the template for those special cases by passing a :template option.

1
2
# renders app/views/forms/_custom_template.html.erb
<%= form.text_field :name, :template => 'custom_template' %>

This is great because you can keep all of your form presentation in one area. It keeps them DRY.

It’s worth noting the variables that are automatically made available to each template (see line 90 of form_assistant.rb).

1
2
3
4
5
6
7
8
locals = {
  :element => element, 
  :label => label, 
  :errors => errors, 
  :tip => tip, 
  :helper => helper, 
  :required => required
}

To get started with basic templates, run this command from your project root:

1
$ rake form_assistant:install

That will create a /forms directory under app/views and put some default forms in there. Modify them at your own will (it’s recommended, actually).

Labels

Labeling form fields is a tedious task, but it’s important, too. Here’s how you can work with labels using the form_assistant:

1
2
3
4
5
6
<%= form.text_field :title, :label => 'Project Title' %>
<%= form.text_field :title, :label_text => 'Project Title' %>
<%= form.text_field :title, :label_class => 'required' %>
<%= form.text_field :title, :label_id => 'dom_id' %>
<%= form.text_field :title, :label => { :text => 'Project Title', :id => 'dom_id', :class => 'required' } %>
<%= form.text_field :title, :label => false %>

If you don’t do anything, the label will be a humanized version of the field name by default.

Defaults and Configuration

There are a few things you can customize that will change the way the form_assistant behaves, globally.

1
2
3
4
5
6
# config/initializers/form_assistant.rb

RPH::FormAssistant::FormBuilder.ignore_templates = true # defaults to false
RPH::FormAssistant::FormBuilder.ignore_labels = true    # defaults to false
RPH::FormAssistant::FormBuilder.ignore_errors = true    # defaults to false
RPH::FormAssistant::FormBuilder.template_root = '...'   # defaults to app/views/forms

Examples and Bonus Features

Using fields_for alone won’t automatically give you form_assistant niceties. You must call it in the context of the form object, and then it will work as expected.

1
2
3
4
5
<% form_assistant_for @project do |form| %>
  <% form.fields_for :tasks do |task_fields| %>
    <%= task_fields.text_field :name %>
  <% end %>
<% end %>

You can set a required flag (maybe used for a CSS class or a ”*” or something) by simply passing it:

1
<%= form.text_field :title, :required => true %>

There are a few other things, such as easy cancel links:

1
2
3
4
5
6
7
8
9
10
<%= form.cancel %>

<span class="cancel">
  <a href="/wherever/the/user/came/from">Cancel</a>
</span>

# other options:
<%= form.cancel 'Go Back' %>
<%= form.cancel 'Nevermind', :path => some_path %>
<%= form.cancel 'Go Back', :attrs => { :class => 'go-back' } %>

See for yourself how easy it is to add your own custom helpers to form_assistant.

Also, make sure you’re aware of partial and fieldset, too, as they’re extremely useful (thanks, Chris).

See the Docs

It’s seriously advised that you go through the README, as I haven’t quite covered everything in this post. It (the README) will serve as the most up-to-date documentation for the time being.

Conclusion

Hopefully this post will take the place of the out-dated one, and assist any confusion thereof. I personally think forms are the most tedious thing to deal with in a Rails application, and this plugin has severely improved my code.

If you don’t want to use my plugin, you should at least explore the options for creating your own—it’s worth the time and the effort, I promise.

As expected, you can find it on GitHub. Enjoy.

Comments

01

Danny on Wed Mar 11 at 08:23AM

Hi!

Great update.
I do have one suggestion:

It is possible to set an empty error on an activerecord field like this:
@user.errors.add(:email, "")

I want to do this because for example if the login fails i give an error on base instead of a specific field.
I do set the empty errors so the fields get market as error.

Now in your has_errors? method you check if a field has errors by calling object.errors[field].blank?

I suggest you change this to object.errors[field].nil? so you support empty errors.
Then i can do something like this in my template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="form-row<%= (errors.nil? ? '' : ' form-error-row') %>">
  <div class="label">
    <%= label %>
    <% if tip %>
      <span class="tip"><%= tip %></span>
    <% end %>
  </div>
  <div class="field">
    <%= element %>
    <% unless errors.blank? %>
      <div class="form-helper form-error"><%= errors %></div>
    <% elsif required %>
      <div class="form-helper required"><%= t("forms.required_field") %></div>
    <% end %>
  </div>
</div>

Thanks

02

Zac Zheng on Thu Dec 17 at 11:40AM

I use your plugin regularly and love it for its utility.

I sometimes come to a situation where the whole form is using assitant_form but I would like some fields NOT to be. This happens when I need more control.

I am having difficulty achieving this. I have tried this for fields that should not use assistant_form:
- f.fields_for :web_page, @web_page, :builder => ActionView::Base.default_form_builder do |ff|

or :builder => nil

But neither works and I’ stumped. Can you offer any advice on this?

03

Ryan on Thu Dec 17 at 02:55PM

@Zac Zheng -

Yes, there is a way around this. Try passing template => false.

1
<%= f.text_field :title, :template => false %>

Let me know if that didn’t fix your problem.

As for the fields_for situation, you could try neglecting the form object (f in your case). Something like:

1
2
3
<% fields_for :site, :web_page, @web_page do |ff| %>
  ...
<% end %>

I think that would revert back to its normal behavior, as the form assistant builder lies in the form object, so if you don’t use it, fields_for is none the wiser.

04

Paul on Mon Jan 25 at 01:21PM

Quick q:

Can I add a spinner? I’m using form_assistant to upload large files. Currently, I don’t have anything to show the user that the request is still in process.

Thanks!

05

Ryan on Mon Jan 25 at 01:37PM

@Paul -

That should actually be something that is handled via javascript. If you’re using jQuery, you could do something like this:

1
2
3
$('input[type=submit]').click(function() {
  $(this).val('Working...')
})

That would change the button to say “Working…” when it is clicked. Or, if you’re using Ajax and looking for something more universal, like a loading graphic, you could do something like this:

1
2
3
4
$.ajaxSetup({ 
  'beforeSend': function(xhr) { $('#loading').show() },
  'complete': function(xhr) { $('#loading').hide() }
})

That would show an element with a DOM id of ‘loading’ anytime an Ajax request was performed – so you could put whatever you wanted in there, a message, a spinner, etc. You could also set it up with content_for if you wanted custom loading messages per view.

Let me know if you need further help with your spinner issue, but I’m sorry to say that it’s not something that form_assistant should be concerned with.

Thanks!

06

Paul on Tue Jan 26 at 10:58AM

Thanks for the response. I’ll dig into this later today and let you know how it goes.

Have something to say?
Protected by Defensio Formatting Tips

or

Copyright © 2010 Ryan Heath | Site Management A Ruby on Rails production.

This site is a Formed Function. Formed Function LLC | @formedfunction | Get in Touch