Rails Complex Forms + jQuery == Headache
See update at the end for a solution that doesn't go back to the server.
A co-worker came to me today with a problem where he couldn't make his code DRY. He is using the concepts from Railscasts #75: Complex Forms Part 3 to create and update a model and its associations in a single form. Where Railscasts #75 breaks down for him is he is using jQuery for the project. Until Rails 3, jQuery and RJS just don't mix. Since RJS is the mechanism for inserting the partial code for new associated models client side in Railscasts #75 this was a problem.
His original solution was to basically re-create the partial in a javascript function that uses jQuery. This was the not DRY part. Everytime he updated the partial he needed remember to update the javascript version of that partial too.
As I was getting ready for bed tonight, I thought of a solution to the problem. This, of course, has delayed me getting to bed at a reasonable hour as I didn't want to forget it. It's a little bit of a hack (actually not too bad), and puts the partial code in one place. I haven't tested this with rendering existing tasks with edit, but since I didn't deviate from Railscasts #75 code that much, I expect it's real close to working if it doesn't work already.
This solution takes the concept from Railscasts #75 and adds a custom REST action (as shown in Railscasts #35: Custom REST Actions) to render the partial for inserting into the form with jQuery. It's actually very little code to serve up the partial for jQuery.
The additional code beyond what is prescribed in Railscast #75 is as follows:
// config/routes.rb
map.resources :projects, :collection => { :task_partial => :get }
// app/controllers/projects_controller.rb
def task_partial
@task = Task.new
respond_to do |format|
format.html { render :action => 'task_partial', :layout => false }
end
end
// app/views/projects/task_partial.html.erb
<%= render :partial => 'task', :object => @task %>
// app/views/projects/_fields.html.erb
<%=link_to_function 'Add Task', "append_partial('#tasks', '#{task_partial_projects_path}');" %>
// public/javascripts/application.js
function append_partial(target_id, partial_path) {
$.get(partial_path, null, function(data, status, xhr) {
$(target_id).append(data);
});
}
Update
There is a much better solution to this problem. You can get rid of the call back to the server by replacing the Add Task link in Railscasts #75 with the following:
// app/views/projects/_fields.html.erb
<%=link_to_function 'Add Task', "$('#tasks').append('#{escape_javascript render(:partial => 'task', :object => Task.new)}')" %>
This eliminates the need for the changes in config/routes.rb, app/controllers/projects_controller.rb and public/javascripts/application.js, and the need for the existence of app/views/projects/task_partial.html.erb as well.
Essential Reading for Developers: What About the Database?
A couple months back I posted a list of my recommended books (videos) for any developer (especially those fresh out of school) to read. One hole in my list was something covering database design. Not because I didn't think it was important. I couldn't find the right book to fit with the rest on that list. That list is about good foundations and not exhaustive coverage. One other important thing was ease of reading (with the glaring exception of About Face 3 which still irks me).
Anyway, to the point of this post. I think I have found the book I was looking for. Beginning Database Design: From Novice to Professional from Apress. With this addition to my list it looks like the following (in roughly the order I would read them in):
- Head First Object Oriented Analysis & Design
- How To Design A Good API and Why it Matters
- Beginning Database Design: From Novice to Professional
- About Face 3: The Essentials of Interaction Design
- Head First Design Patterns
- Inversion of Control Containers and the Dependency Injection pattern
Again, I encourage everyone to read more then this. This is just where I would start.
AjaxWorld and Appcelerator
I am in San Jose this week for AjaxWorld and to meet my new co-workers at Appcelerator. For the conference Appcelerator put me up in the very posh Fairmont. Great room.
The conference it self was pretty good. Worked the booth mostly and only got to see a few presentations. Some were great, other less so. I answered "What is Appcelerator?" more times then I care to guess. That got boring. There was much more variety of topics to cover at CUE.
The folks at Appcelerator are nice. I think it will be fun and easy to work with them. They are very receptive to new ideas which will be a nice change of pace.
Advertise Here... No Here!
I just read an article who's accuracy I cannot verify (or choose not to anyway), but I am all for. Reportedly, Air New Zealand is paying people $660 a pop to shave their head and temporarily tattoo one of their ads to their head. I am all for this.
Anyone want their ad on the back of my head at AjaxWorld in the form of a temporary tattoo? My cranium is available cheap.
Essential Reading for Developers
As I made the rounds on Friday letting some folks know that I will be leaving Lawson one of them asked me what I thought was essential reading for developers. I told him that it was the books we were reading for the book group I started at Lawson.
Upon further reflection this is good information to pass along. So here it is. If you want to write software and you will read (or watch) nothing else, this is what I recommend. It's Java heavy in it's examples but concepts apply to any OO language.
- Head First Object Oriented Analysis & Design
- How To Design A Good API and Why it Matters
- About Face 3: The Essentials of Interaction Design
- Head First Design Patterns
- Inversion of Control Containers and the Dependency Injection pattern
There are other good reads to be sure, but this is where I would suggest someone to start when they are fresh out of school.








