Create reusable form partials in Rails

If you’ve got an admin part in your rails app and some settings to take care of, chances are that you have a lot of similar data. And what can be more wearying, than creating all those forms, index/edit/new views over and over again? Of course you could use the scaffold, but I personally strongly dislike it.

So I figured out I try to make my partials variable as possible. This post shows you how you can create highly reusable form partials.

My structure is as following:

There is an admin panel. Inside admin panel there are settings (which get repetitive) and inside settings you can manage models like “colors”, “patterns”, “fabric” (you can guess it – it’s a clothing online shop). All of them contain identical data, but have some differences as well.

I’ve got only 3 views – index, edit and new, because there is no sense for having a show view, as it should be the edit view right from the get go. This said, we need only two partials – one, for listing items inside our index view and one for creating and editing existing data.

Let’s start with routes.rb:

Simple dashboard when you visit plain old “/admin” and then resources inside another namespace “settings”.

My index view – index.html.haml:

As you can see, I pass 3 local variable to my partial (this is the only thing you need to edit for each model. But hey, it’s only 3 words!) – the russian name, so I can have some customized buttons and links. The current collection and the name in english.

Listing items partial (a.k.a. index)

Well, apart from some html, the important things are:

  • to check if there is at least one item in the collection (remember, we pass the collection under the name “current_objects”)
  • for each object in current_objects we access it using the variable “object”
  • since our partial is variable we can’t use hardcoded paths, like “admin_settings_colors_path”. Meaning we must make use of the “send” method, which basically makes a method from a string. To pass parameters to a method created by “send” you simply put this parameter as a parameter to the send-method.  send("hello_there", caramba) is equivalent to calling method hello_there(caramba)
  • Because “object” is actually an object (wow!) we can’t use it in the path generation. This is why I pass “single” as a local variable. “Single” is simply the singular form of the model (category, color, pattern etc.)

My edit/new view:

They are absolutely identical.

I render some flash messages to tell users about successful or failed actions. Then I render my second partial using again a local variable to transmit the collection.

Form partial

The core 🙂

Well, again a lot of HTML, but I will summarize the core points for you:

  • First of all we build our form using triple nesting  =form_for [:admin, :settings, current_objects] do |f|
  • Now comes the most interesting part – surely your models will differ a bit. Maybe on has images to upload, the other doesn’t. One has a price tag, other don’t. Etc. and so on. Thus, we need to create an all-purpose-form, disabling fields when not required. This is done by  respond_to? method. You can see it in this line   -if current_objects.respond_to?(:picture) This basically means, that if there is no :picture method for current object, the block below won’t be executed. Nifty, eh?
  • In my example every model has a field, called “name”, this is why I don’t check for it. All other fields are encapsulated in a respond_to? check.

Resume

With just a few methods – send and respond_to? you can create highly reusable partials where your maintain effort goes towards zero. Only one file for each action (index and edit/new) – truly amazing!

Published by

Anton

Hello! My name is Anton. I am a passionate project manager who loves digging deep into code. You can check my Github and CodeEval. Hopefully my thoughts on management can lead you to one or another good idea.