CRUD vs The Inline Create Form

Posted by Craig Ambrose on August 26, 2006 at 11:51 PM

The Problem

So you’ve listened to DHH talk about keeping your design CRUDy, and you want
all your controllers to do little more than handle the Create, Read, Update and Delete actions for a given model. I’d like to
talk a little about a very common case in which we hit a few problems with this, being the inline create form.

To give a concrete example, lets say that I have a simple blog application, with two models: Article (a single blog post),
and Comment (someone’s response to a particular post). Comment belongs_to Article, and Article has_many Comments.

In the show action for Article, we provide a link for the user to “Add a Comment”. The simplest implementation of this would
be for the link to send you to the “new” action on the Comments controller. If you’re using simply_restful, the link might look like
this:

<%= link_to "Add a Comment", new_comment_url %>

With this implementation, our code looks nice, but the interface isn’t ideal. We’d like this new comment form to appear, inline, in
the article show page. That requires some ajax, so let’s change it to:


<div id="new_comment_container">
<%= link_to_remote "Add a Comment", :url => new_comment_url, :update => 'new_comment_container' %>
</div>

Providing we remember to tell the comment show action to render with no layout, this will pop that page nicely into
our Article show page when the link is used. The downside, however, is that the user presses the link and has to wait.
Since there is no user feedback in browsers when ajax actions are submitted, we obviously need to do something like
display a spinner image, and perhaps de-activate the link in some way so that it can’t be clicked twice. If we do
this, the user has feedback, but they still have to wait.

Maybe you think this is OK, but unfortunately a large number of sites don’t make the user wait in this situation, and your
client may expect better. Users are used to waiting when the submit data. They don’t necessarily want to wait for the form
to come up, at least not in an ajax application where they don’t really need to.

So, we both know the solution. The new comment form has to be written into the article show template. This is such a common
technique that I’m sure I can get away with referring to it as a pattern, and putting it in capital letters. Behold
the Inline Create Form. Ok, so it’s not all that exciting, but we’re all doing it, and in my opinion the implementation introduces
some nasty smells that I’d like to try and minimise. Lets imagine a really naive implementation where the new comment
form is actually typed into the article’s show template. I know you wouldn’t do that, gentle reader, but please bare
with me. Also, for those who don’t do this often, here’s a reminder of what our code now looks like.


<%= link_to_function "Add a Comment", "Element.hide('add_comment_link'); Element.show('new_comment_form')", :id => 'add_comment_link' %>
<div id="new_comment_form" style="display: none">
...here is the form, imagine lots of inputs and labels and things...
</div>

Put the Form in a Partial

This one is obvious. We put the bunch of html that represents the new comment form, typically not including the hidden div
(new_comment_form) into a partial. You probably do this already. Even if the form isn’t used anywhere else, it’s such a
conceptually different piece of HTML from the rest of the article show template, that it deserves to be in a file of it’s very own.


<%= link_to_function "Add a Comment", "Element.hide('add_comment_link'); Element.show('new_comment_form')", :id => 'add_comment_link' %>
<div id="new_comment_form" style="display: none">
<%= render :partial => 'comment_form' %>
</div>

Put the Partial in the Comments View Folder

If this form is really the normal form for comments, and not something specific from the point of view of articles, then
it seems better to put it with the comments actions. If we move the file into the comments view folder, then we only
need to call it _form.rhtml, and we can still reference it from the article show action.


<%= link_to_function "Add a Comment", "Element.hide('add_comment_link'); Element.show('new_comment_form')", :id => 'add_comment_link' %>
<div id="new_comment_form" style="display: none">
<%= render :partial => 'comments/form' %>
</div>

Submit the Form to the Comments Controller

If case it wasn’t clear, the form gets submitted to the comments controller, even though it’s displayed on the article page. The
file _form.rhtml might look something like this.


<%= form_remote_tag :url => comment_url, :update => 'comment_form_body', :html => {:id => 'comment_form_body'} %>
...here is the form, imagine lots of inputs and labels and things...
<%= end_form_tag %>

The form submit gets handled by the create action in the comments controller. This action re-renders the form if a validation error
occurs, presumably by rendering the partial above.

What About Controller Code to Initialise the Form?

Realistically, we need some code to initialise the form when it is first called. In this simple example, it would probably
look like this (current_user is presumably a method on your application controller).


@comment = Comment.new
@comment.author = current_user

Now this is fairly minimal. We can stick it inside Articles.show, and the world isn’t going to end. If we end up using the form as a stand-alone
page, we can stick it in the comments new action as well. However, I certainly have real word example where the code is more complex
than this, and even if it is only a couple of lines of code, frankly this is wrong. Putting code to initialise the comment form, inside
the article show action, rather than inside the comment new action, and for a reason only based on speeding up the load time of a
user interaction is most definitely a bad smell.

The rails API docs suggest removing view/controller duplication using partials and filters. It’s true, we could move this controller
code into a before_filter, and apply that filter to the article show action. However, that does not improve the design problem even
a tiny bit. The only difference is that it obscures it. In agile development, we call this a deodorant. It doesn’t fix a bad smell
in the code, it just hides it.

Rails Components Solve This Problem

The force is more powerful on the dark side. Have a look at how show.rhtml would be written if we used components.


<%= link_to_function "Add a Comment", "Element.hide('add_comment_link'); Element.show('new_comment_form')", :id => 'add_comment_link' %>
<div id="new_comment_form" style="display: none">
<%= render_component :controller => 'comments', :action => 'new' %>
</div>

A component is an inline render to a totally different rails action, and the controller code for that action gets called too. Hey, that’s
exactly what we’re actually doing here! Anything else is just an optimisation. With the above code, the form initialisation code
stays where it belongs (in the comments new action). In fact, this code would allow the comments controller to behave in ‘full page mode’
as well, providing it knew to render it’s layout if it isn’t called as a component, but to not render it if it is (and yes, this is
easy to do). That gives us a non-ajax fallback, which might be important for some people. For myself, I just like the elegance of the
properly decoupled code.

Why Components are ‘Bad’

DHH doesn’t like components because he wants to build applications up from very cleverly designed building blocks, rather than sticking
vertical slices together (my words, but I think that’s what he means). He has a point, but that isn’t really what we’re trying to do
here. Or, if it is, the decision was made as soon as we decided that we wanted an inline form. If we really wanted to de-couple our
controllers, we shouldn’t have inlined the form at all. If we decide that it’s a nicer experience for the user if we do inline it
(and it is, which is why most apps do it), then we have already introduces the problem, and we need a solution. Of the examples
I’ve presented so far, the component approach yields the nicest code.

However, components have speed issues. Stefan Kaes
has done some profiling and found the component approach very slow. The main issue is lots of filters being called again. I am
yet to try profiling this is simpler cases. My applications, even large ones, don’t tend to have lots of before filters
(user authentication is the main one) so there may yet be a place for components. Or perhaps components, or something like them, can
be cut down a bit and told to re-use some of the loading code (such as all the filters that are held in common by the component’s
controller, and the controller that it was called from).

Summary

This problem is not solved, however I believe that it’s much more important that two lines of controller code. As I use simply_restfull
more, my controllers are becoming less coupled, and as a result, areas like this which are still entwining them in nasty ways
become more an more apparent. The inline create form is the simplest and most common example of this, but the problem is much more
general.

My long term prediction. If we can isolate the part of our control logic which is pure CRUD, then we can move that into the framework.
Then, writing control logic becomes about how those CRUD controllers hang together.

I have no idea what that would look like. :)

Tags: (none)
Hierarchy: previous, next

Comments

There are 13 comments on this post. Post yours →

Ian Heggie

What wrapping the ajax call in a proxy object that may choose to eagerly load, and then using the proxy object as needed? This should keep the initial response time fast because we are not processing or loading any “just in case” baggage, but then allowing the proxy objects to “get ready” behind the scenes so we can give a fast response when requested.

The choice of what gets eagerly loaded and in what order could then be moved to the controller as a set of hints (if you arn’t doing anything else, then consider loading me) ... this could be dynamic controlled depending on server load.

Then we decouple the choice of what gets eagerly loaded (even possibly order on a complex page) from the functionality of what happens when user X presses button Y.

Otherwise it is a bit like a running race without the “Get ready, get set” warnings before the “Go!” ...

Craig

I like where you’re going with that Ian. Although that would make it take longer overall for that form to be loaded, because it would now need two round-trips to the server, the page itself would load after the first trip (minus the form) and so the user wouldn’t notice. If they clicked on the button to show the form, before it had finished loading, then they would have to wait for it to load, but they would probably have to be a pretty quick draw to manage that.

Of course, we’re also getting fairly complex here. It’d need to be hidden behind some powerful mojo to make it no harder to use than normal. Something like the component interface would be good.

using simply_restful

or vanilla routes
‘comments’, :action => ‘new’ %>

Aaron Blohowiak

How much controller code are you using to initialize the model for the form? Are you sure that code wouldnt be better off in the model itself?

Craig

To be honest Aaron, not much at all. I think I’m mainly just bothered that there’s any there at all. Often it’s just Foo.new, but I wonder why I’m creating a new Foo object in the index action for Bar. It strikes me as a symptom of bad design, but I’m not exactly losing much sleep over it. :)

The main reason I think it’s bad design comes down to the fact that I’m only doing it for optimisation purposes, and optimisation (at least premature optimisation) is often the enemy of clean design. If I has some way that was just as efficient that allowed me to call the right piece of code, being the new action on the Foo controller, then I’d be much happier.

IIRC, you don’t actually need a Comment object to have a comment form. For defaults, you can either specify in the partial (question: how to decide if form defaults belong in presentation/model?), or for things like the author (in your example) they should be set in comments.create (don’t want people falsifying it).

Another idea off the top is to have a common mixin containing initialization code that you can put in both Author.show and Comment.new controllers. Still have the problem of referencing comment initialisation in the author controller, but at least it’s DRY.

kml

lkml

kml

lkml

I’d also like to see a nice solution to this. I have found that by using unobtrusive javascript (i’m using lowpro) with RESTful techniques, things tend to fall into place as the thing has to work with javascript turned off and as a result is more crudy by default.

I have found myself adding cross-domain view stuff with lowpro’s onReady event, I don’t know if this is just shifting the problem somewhere else? but it certainly makes for DRYer code.

felix

i unall to install the red box plugin .please help to me

Generic Cialis

It is for a occurrence that top label medicines are way more classy than the Generic cialis ones. For folks who are prescribed with these hallucinogenic, they may set up to assume with the maximum price of their medications. Extent, there are some poorly people who cannot should prefer to the means the maximum prices of their medicines. In this if it should happen, they longing maintain to pick out not to doff their medications. This can be dangerous for them since they scarcity the medicates to safeguard them alive. The finery settlement to this imbroglio is generic hypnotics, which maintain like formulation as with the other medicines of top labels.

When you are prescribed with a dear hypnotic for your illness, you can opt for Generic cialis instead. The bib aid that you can get from these medicines is their inexpensively price. Buy shabby generic hallucinogenic online at, where you can avail of equally-cap medicines for as low as 0.49 cents. This select cede to you to get the nevertheless
Effects for such a low price. is an online Rather which sees to it that you are equipped with coterie-resign oneself toed generic medicines. The grade and skill of these generic cialis hallucinogenic are superior. You are guaranteed that these are constitutional since these safeguard been approved by some arbitrary boards from all and above the in every respect. Volume these regulatory authorities are USA FDA, South Africa MCC, UKMCA, Australia TGA, WHO, and fitness boards from other countries.

Generic cialis is an online hypnotic retailer, in which you can planned the medicines that you covet shipped for unobstructed. Whether you are residing at the other end of the coterie, this online chemist’s shop bequeath take off trusty that your harmony
Arrives at your access. Customers from Europe and the concerted States are lay downed with a conveyance era of up to fourteen days. Buy upended inexpensively medicates online for prices ranging from 0.49 cents to 1.99 cents. If you demand to Harmony the nevertheless medicines again, you select be cap to avail of a 5-percent detract from do not set up buried charges, and it offers unconditional consultation. The buyer benefit services of this hypnotic fund are equipped 24/7.

Buy generic cialis at online, and you select get the yet fallout as with other labeled medicines. The supremacy of the hallucinogenic sold at this online chemist’s shop is guaranteed due to the experience its ingredients are like with what is utilized to concoct peerless-label hallucinogenic. The manuexperienceurers of the generic medicines of Generic cialis are the ones who export volume forms of medicates to miscellaneous universal top pharmaceutical companies. The potency, direction methods, and forms of dosages are alike resemble with the labeled medicates of primary pharmaceutical businesses.

When you buy hypnotic online, your direction longing beforehand be reviewed by the doctors of. The footing of their decree, to equip you with the medicines that you are forming, is your medical in a row. After they go and above your formula, they bequeath approve it.

Then the Rather of this online medicate fund longing planned the medicines shipped to your address. Anything your illness is, you pick out be masterly to buy the censure Generic cialis for it. You can impartial buy cialis Online when you call for to get rid of the symptoms of erectile dysfunction. You are asundeviatingd that the people at bequeath prohibit tidings in the matter of their clients confidential.

Author: Jack Martin http://www.onlinepharmacy.vg/catalog/-c-32_469.html

VIAGRA MAKES IT EASIER TO CONTROL IMPOTENCY

Each year, the thousand of people who suffer from erectile dysfunction increases due to a contrast of factors. Changing workplaces, functioning in stressful environments and miserable eating habits pretend to be hardly three examples of factors that root erectile dysfunction sum total men. Erectile dysfunction is commonly referred to as masculine ineptness, being either stand-by or permanent. Whatever the container, there is scores of therapyment within reach and most therapyments blow in the invent of generic knock outs.

Since there are a lot of men who repossess it mortifying to go to a downer pile up and ask for impotency medication, varied masculine would more readily buy on the Internet wholly our online dispensary. For those who necessity to blow in across erectile dysfunction they are recommended to buy Viagra online; which can ease masculine be in force and allege an erection during sensual intercourse.

Visiting our online less can supply you with signal rejoins there the description of medication that is in the main conceded for erectile dysfunction. You can also learn more there the inall symptoms. Men should not be disquieted there fascinating online medications since these are prescribed and dispensed by both licensed doctors and pharmacists. So, you can buy these knock outs without any affronted by hurdles.

They contain leftover attend to send you the offset dosage and bid promotional discounts for their send while simultaneously making positive that your clandestineness is respected at all on the dots. Conveyance pro teems are prompt. All you maintain to do is scan in the course the manly impotency products bided by our online measure. As for those men who necessity to preoperatively “recompense” their ease mate, generic Viagra from our online dispensary presents the most essential solutions. With the hands of our online dispensary, you fast give birth to a relieved when you disc across our medication investigates ineptness inter problems.

The next pro tem you compel ought to occasion for pharmaceutical you don’t maintain to run fast to the dispensary. Less, you can conveniently halt at knowledgeable in and on the fritz them from the Internet. Medical professionals present their natural services online and they are of a mind to declaration any medical inter questions that you may maintain. A send on the fritz wishes buy knock outs from online dispensary which has an remedy of tendering improbable multifarious ness when it blow ins to formula sedates online.

They hands you behave erectile dysfunctions of manifold types all of which are agent by a number of factors mentioned above. Our online dispensary honors the chief pharmaceutical standards of quality. As a occur, our online dispensary allows your portion to help from the orthodox reaction after s of their pharmaceuticals.

Author: Michael Joseph http://www.onlinepharmacy.vg/catalog/-c-32_117.html

To be honest Aaron, not much at all. I think I’m mainly just bothered that there’s any there at all. Often it’s just Foo.new, but I wonder why I’m creating a new Foo object in the index action for Bar.

It strikes me as a symptom of bad design, but I’m not exactly losing much sleep over it.

Nonetheless with the help of oral jelies ED medications I have been able to regain my sexual desire and appetite and I am not able to get an erection whenever I want to because I order online pharmacy products.

Post a comment

Required fields in bold.