Posted by Richard White
Wed, 12 Apr 2006 20:32:44 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
Well that didn’t take too long, about 3 hours by my count, to find the first egregious bug in the 3.0.0 code. Thanks to Daniel to pointing out that I had left some hardcoded values in ajax_scaffold_helper.rb that were screwing up pagination. Regardless, I’ve put out a patch for this issue, anyone care to guess how long before the next bug strikes :)
Posted by Richard White
Wed, 12 Apr 2006 17:51:00 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
It’s finally here…

Lets get right to it, here are the major changes:
- Generated scaffold uses RJS templates. This should make adding and changing behavior much easier, but this also means that Rails 1.1+ is now required.
- Sorting & Pagination support.
And some of the minutae:
- controller/list now shows the scaffold in a layout and the component’ized version has been moved to controller/component. This is more in keeping with the standard scaffold URLs.
- Wrapped rescues around all CRUD database calls and output the error message using flash[:error] (see below)
- The default render_component call now passes along any parameters
- Scaffolds can be passed a parameter of :scaffold_id. Useful for when you want multiple scaffolds of the same type on one page (eg You are doing scaffolds inside scaffolds for parent-child associations).
- Backend fields (created_at, created_on, updated_at, updated_on) excluded from generated forms by default. Changing the generator to modify this exclusion list is pretty straightforward (I’ll explain this later), however it currently cannot be done at generation time with an argument.
- Default formatting for date and time fields in the list view that isn’t so verbose. They currently default to a more terse US-centric formatting, but its very easily modified (explained later as well).
- Indicator now goes clockwise
- No longer generating migration files which were oftent causing conflicts.
And one feature regression:
- Fade and highlight effects have been removed temporarily. If you saw the awful workaround code I had in the last version for getting the highlighting working correctly you know why. I decided to cut bait on this feature for now since the amount of work to get an elegant solution was more than I was willing to invest at this point. Someone forwarded me the Fade Anything Technique that looks dated but promising, if anyone wants to tackle this issue please by all means be my guest :)
You’ll still want to have perused the original howto article for how to install and run the generator and probably a good idea to just play around with the demo before proceeding. I’ll update you on changes to a few key things you might need to get you started on customizing your generated scaffolds.
System Messages
Previously messaging support was very limited. You could only render an error message and only in certian methods. Let’s just pretend that was all just a bad dream and move on. Sending a warning message to the display now is as easy as:
def create
begin
@widget = Widget.new(params[:widget])
@successful = @widget.save
rescue
flash[:error], @successful = $!.to_s, false
end
<strong>flash[:warning] = "Watch your back, they're everywhere!"</strong>
...
Thats it! Now that message will be inserted at the top of the scaffold after a new widget is created.

There are three supported message types :error,:warning and :info. Had @successful been false in the last example then the message would have been inserted into the form instead.

If you look in the RJS templates for each of the CRUD methods you can see whether it will post the message to the list or to the form, but its pretty intuitive. If there is a form open after the action is called the messages go there otherwise they are put at the scaffold level. One thing to note is that each request overwrites the existing error messages.
Changing data formatting defaults
The default formatting for certian data types in Ruby was really getting on my nerves, especially those for dates and times. Thus I redirected the display formatting of object values through a method so I could inject my own defaults. You can modify the default formats or add your own special formatting for specific data types by editing the following methods in app/helpers/ajax_scaffold_helper.rb:
...
def column_value(data_object, column)
column_value = data_object.send(column.name)
if column_value.instance_of? Time
column_value = format_time(column_value)
elsif column_value.instance_of? Date
column_value = format_date(column_value)
end
column_value
end
def format_time(time)
time.strftime("%m/%d/%Y %I:%M %p")
end
def format_date(date)
date.strftime("%m/%d/%Y")
end
...
Customizing the table data display
This was a very crappy way to solve this problem. We have a much more robust solution in 3.1.0
By default the data you see in the scaffolded table is exactly the same as the fields in your database table and even in the same order. You can modify data columns by using the lib/content_columns_patch.rb and overriding self.content_columns in each model class. First, add require ‘content_column_patch’ to either the model or to environment.rb. Then add the following to your model:
class Widget < ActiveRecord::Base
def self.content_columns
get_desired_columns %w(version name), @@desired_columns_cache ||= nil
end
...
The second argument in that call simply passes in a class variable to use as a cache for the columns so they don’t have to be refiltered everytime content_columns is called. Now your table data display will be restricted to just the version and name columns and displayed in that order.
Overriding Scaffolding & Modifying globally excluded form fields
Many people have asked how they can modify the generator so that they can tweak the scaffold output on a more global level. A good example is if you wanted to change the list of fields that were ignored by the generator when creating scaffold forms. You’ll find the default list in templates/form_scaffolding.rhtml in the Ajax Scaffold Generator directory:
<%= all_input_tags(@model_instance, @singular_name,
{ :exclude => %w(created_on created_at updated_on updated_at) }) %>
Modifying this file would change all subsequently generated scaffolds, if you wanted your changes localized to a single project you can always copy the generator files (all the files under ajax_scaffold_generator-3.0.0) into lib/generators/ajax_scaffold.
Wrapping Up
Your responses will drive where development goes from here, I’m pretty happy with where it is for a least a little while. Perhaps long enough for me to catch up on other projects. I’ve reluctantly (I say reluctantly because I find 16bugs’ design and usability repulsive, but I don’t know a good free alternative… I miss Mantis) set up an account on 16bugs so submit any bugs there. Feel free to leave any questions or comments you have below. Happy generating.
Posted by Richard White
Tue, 04 Apr 2006 19:06:00 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
I just wanted to give everyone a bit of a status update on the next release of the AjaxScaffoldGenerator. It is progressing nicely: a lot of bug fixes, support for more robust messaging, sorting and pagination are 90% complete (which is to say that they just need a bit of polish). The main thing holding it up now is that I am converting everything over to RJS templates.
For all the talk about how to migrate scaffolds, I’ve basically made that whole conversation a moot point for the next release. It was a tough decision, but after my work on it last week I realized that I was just having to change too many things and with Rails 1.1 released I might as well make a wholesale change.
On the plus side you’ll be able to modify individual scaffold behavior since each scaffold won’t have to share a generic javascript handler with all the other scaffolds. On the negative side, if you were holding out on Rails 1.1 it will now be required.
As always any thoughts on this development are appreciated.
Posted by Richard White
Thu, 23 Mar 2006 19:53:00 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
A number of you have emailed or left comments asking about how to go about migrating your scaffolds
as new versions of the generator come out. The current answer of course is that there is no automatic
migration facility you would have to generate a new version of the scaffold and do a diff. I’m wondering what
the community of AjaxScaffold users thinks should be done about this. After the next two releases (which will
add pagination and sorting) I expect the release cycle to become much less frequent. Here are the options on the table,
as I see them, in order of difficulty:
- No migration support. After the next few versions you should be set for a while and not have to worry about migrating
more than a few patches here and there. This still might be quite the headache for users that have heavily modified
their scaffolds. If you haven’t done much modification you can just regen a new scaffold and port over any minor changes
you made.
- Write up specific details of what has changed and how to work that into existing scaffolds.
- Putting out diffs of between scaffold versions for how to migrate one to the other. This is something anyone could do
and if anyone wanted to volunteer to do this I would be very grateful hint hint
- Create a sister project to the generator that is equivalent to the :scaffold facility the standard Rails scaffold has.
This would be an alternative for those people that make only minor modifications to the scaffolds. The could include :ajax_scaffold
in their controller and just SVN up to get the new features. I honestly don’t know how much work that entails for me but I assume
its more than the former options.
The implied question for all of you out there is: do you find yourself using the scaffolds as they are? do you modify them a little?
do you modify them a lot?
Posted by Richard White
Tue, 07 Mar 2006 23:10:32 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
Real quickly the changes:
That has been fixed by changing all instances of controller_name with controller_file_name in the generator templates. Thanks to Sam and Ian for pointing out this bug.
Posted by Richard White
Tue, 07 Mar 2006 01:38:00 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
I’ve been promising a number of you articles about how to do various, and common, customizations of your Ajax scaffolds. Rather than try to cover all your questions in one voluminous post I’ll try to tackle them a few at a time.
This first one will be on two rather simple topics, how to customize the the scaffold columns and how to create an admin console from multiple scaffolds. From here on in I am assuming that you have a least read the introductory article and have generated a scaffold or two. Without further ado, lets begin.
Customizing the columns
There is a much easier way to do this, check out the 3.0.0 release notes
Probably the first thing you want to change after you generate a scaffold are its columns. If you look in _modelname.rhtml (ex: _widget.rhtml) you’ll find the code that writes out the model’s attributes to the table:
<% for column in Widget.content_columns %>
<%=h widget.send(column.name) %>
<% end %>
Using Widget.content_columns is good from the standpoint that it gets you up and running fast but obviously has a number of drawbacks:
- You often end up with a lot of backend attributes like created_at, updated_at and other attributes you probably only need for backend processing showing up.
- Except in the simplest of examples you will have associations (
belongs_to, has_many, has_and_belongs_to_many, etc) that aren’t included.
There is no magic solution to this, just explicitly setting what columns you want to show up. We can replace the preceding code with the following:
<td><%=h widget.name %></td>
<td><%=h widget.version %></td>
<td><%=h widget.owner.name %></td>
So now we’ve specified that we want to display the name of the widget, its version and the name the owner object that is associated with it. This is assuming that we have mapped that association in our widget.rb and there is a model named Owner:
class Widget < ActiveRecord::Base
<strong>belongs_to :owner</strong>
validates_presence_of :name
end
Now we need to also explicitly set our column headers in list.rhtml:
<thead>
<tr class="header">
<th>Name</th>
<th>Version</th>
<th>Owner</th>
<th></th>
</tr>
</thead>
The empty <th> on there end there is for the column with our edit/delete actions. One final change and we’ll be done. If you look in the helper for out WidgetController you’ll see the following method:
def num_columns
Widget.content_columns.length + 1
end
This method exists so that we can set the colspan for any of our inline forms (create, edit) in one place. The +1 is for the cell with the edit/delete actions. So we’ll just explicitly set this as well:
def num_columns
4
end
And there you go, thats all there is to customizing the scaffold object list.
Creating admin consoles using multiple scaffolds
One of the nice things about AjaxScaffolds is how easy it is to combine them to create an admin interface or drop them into existing pages. If you open index.rhtml you find:
<%= render_component :controller => 'widget_console', :action => 'list' %>
Basically this means that the index action for our WidgetConsole controller is already using the scaffold as a Ruby on Rails component, this is good news as it makes it very simple to put these together. We’ll go ahead and create a new controller named AdminConsole and an index.rhtml for it. Then we’ll open up said index.rhtml and add the following lines:
<%= render_component :controller => 'widget_console', :action => 'list' %>
<%= render_component :controller => 'customer_console', :action => 'list' %>
As of release 3.0.0 this should be:
<%= render_component :controller => 'widget_console', :action => 'component', :params => params %>
Now if we go to /AdminConsole we should see both scaffolds on the same page (if you have an WidgetConsole and CustomerConsole controller). That’s it! Granted your page looks a bit bare, but I’ll assume you can setup the rest of the page around them. Similarly you can drop scaffolds into existing pages with the same code.
Did I say “that’s it” well I jumped the gun. There is still one more thing to do. Since you love all your user’s even the cute little ones that don’t have JavaScript enabled you want to make sure they are taken care of as well. So as I wrote in my previous post you’ll need to change both the CustomerConsole and WidgetConsole controllers return_to_main methods to look like so:
def return_to_main
redirect_to :controller => 'AdminConsole', :action => 'index'
end
Make sure that whatever view you drop the scaffolds onto that the following stylesheets and javascript files are in the header of your layout (and in the same order):
<%= stylesheet_link_tag 'ajax_scaffold', :media => 'all' %>
<%= javascript_include_tag 'prototype', 'effects', 'rico_corner', 'ajax_scaffold' %>
There, now you
really are done!
Posted by Richard White
Sat, 04 Mar 2006 22:56:11 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
Just put out a new build to RubyForge, here’s what’s changed:
- Generated scaffolds now gracefully degrade in the absence of Javascript. See the notes further below on some extra setup information associated with this change.
- Refactored some of the CSS class names. Mainly all the stuff that used to be called list and list-wrapper etc are now called ajaxscaffold-list. Makes much more semantic sense and should be easier to work with in the scope of the rest of your application.
- Refactored some of the Javascript code. Minor tinkering like removing all the callbacks for onComplete since they weren’t being used at all.
Yes, I know I said I wasn’t going to do it and could care less about graceful degredation, but it wasn’t my idea… really! You can thank Sean Mountcastle for sending me the code that compelled me to finish what he had started. There is only one real gotcha to the generated scaffold that I will explain below. Also all those other howto articles I promised some of you, don’t worry they’ll be written sooner than later, promise.
Configuring Javascript degredation when using a scaffold as a component
One of the stated goals of this project was to make it easy to create your application by dropping in ajax scaffolds into pages using render :component. If you are dropping in the scaffold as a component on a page that is not /controllername/index you need to modify one method on each scaffold’s controller to make sure everyone gets routed to the right page if Javascript is not available.
If you are using the scaffold in isolation (ie it has its own page which is /controllername/index) then the following code in the controller makes sure that any actions that take the user away from the page (edit, create) return them to the correct page when they finish/hit submit.
def return_to_main
redirect_to :action => 'index'
end
If however you have embedded the scaffold into another page (like an admin console with multiple scaffolds) then you need to modify said method to point to whichever page that may be. For example I modified customer_controller.rb on the demo site to point to the demo page instead of /CustomerController/index
def return_to_main
redirect_to :controller => 'AjaxScaffoldDemo', :action => 'index'
end
Thats it! Now the 0.37% of your users that don’t have javascript will still be able to enjoy those admin consoles you were able to create in 5 minutes with the ajax scaffold generator. </tootingownhorn>
Posted by Richard White
Sun, 26 Feb 2006 21:02:00 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
The feedback from the Rails community has been great. Lots of love and kind words on both this blog and on the responses I saw on the RoR mailing list (which admittedly I don’t keep up with as much as I should, is there any way to get it to digest all the messages for 1 day rather than flooding my inbox with 30 emails per).
I did see some murmurs of bugs on unsupported browsers on one of the responses on the mailing list and there is a list of possible features/improvements (bottom of the orginal howto). I’d like to open it up and see what the community in general would like to see done next. Here are my thoughts on future development:
Sortable rows would be my #1 request. I despise pagination, am often skeptical of most “find” features and find that the ability to sort and scroll are all I need to find what I’m looking for. Sortable Rows +Added in 3.0.0
- A print stylesheet would be easy and a nice touch in my opinion. Print Stylesheet ++
Ability to send different types of messages to the client, not just error one would be useful and easy to do as well. Support information and warning messages as well as error ones ++Added in 3.0.0
- Having it update what other users enter on the screen I think is very important. Otherwise whats the point of it being Ajax if I have to refresh to see other’s changes. But admittedly my current projects don’t have interfaces where there would be multiple people editing the same list so this isn’t as important to me currently. Background list updating +
- I’ll probably get some chastising for these next two but here goes. I don’t find supporting any browsers beyond the existing ones all that important. Something like 4% of the internet uses primarily some unsupported browser. Very edge case to me and a lot more headache than its worth. Supporting more browsers
-
I’m not overly concerned with fallback methods so that it works when javascript isn’t enabled. If javascript isn’t enabled the person is a) not going to be able to use the rest of my application and b) probably isn’t in my core audience anyways. I honestly don’t even know much about fallback methods (tsk tsk I know) since I have no plans on using them (but I should still really learn what they are). Graceful degredation— Added in version 2.2.0
Addendum Thanks to one of our readers for pointing out what should really be my #1 request..
- The generated scaffold should KNOW about and have dropdowns or autocomplete textfields for associations. I know others have ranted about this glaring shortcoming. I think the more scaffolding you generate you kind of resign yourself to the fact that its just not something Rails is going to give you. In fact to make it work I’d have to dig a level deeper than the current AjaxScaffold goes and actually change the base Rails generator. But this really should be a core feature of any interface generator. Anyways I’m putting this on the development stack just under my less ambitious plans for sorting and pagination.
My thoughts are obviously selfish and slanted towards what I need the scaffold for currently, which is exactly the kind of feedback I’d like from everyone out there. So let me have it :)
Posted by Richard White
Thu, 23 Feb 2006 23:38:00 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
This release fixes all of the problems previously mentioned in another post, some minor and some pretty egregious.
I think I finally have the moving of table rows perfected cross-browser which is no small feat. I’ll try and do a writeup in the future of how I solved those insidious problems of moving rows around (and hopefully by then have either a patch for prototype or a wrapper for it to solve all table row insertion issues). But I digress…
Here are the official list of things that have changed in this version, some might even call it a ‘changelog’..
- Safari: no longer crashes browser when editing the last row. (rwhite)
- Row colors always alternate instead of being overwritten by Effect.Highlight.
- Works when you generate with different controller and model parameters.
- Creating a new places that new element where its create form previously was, not at the top as it was previously.
- You now have the option to enable or disable highlighting via the generated scaffold by editing list.rhtml and setting either:
<script type="text/javascript">
TableBodyUtil.enableHighlighting(
AjaxScaffold.getTableBodyElement('customer'));
OR
<script type="text/javascript">
TableBodyUtil.disableHighlighting(
AjaxScaffold.getTableBodyElement('customer'));
- Also a vestigal CSS style of clear: both; on .list-header was removed
You might be asking “Why would I want to disable hightlighting?” Well, in order to make the alternating row colors work with row highlighting I had to set the background color of each table cell to the correct color BEFORE new Effect.Hightlight(); is called. If you don’t do this then Effect.Highlight(); will set an inline style background color on each table cell. Thereby making your CSS style for alternating rows no longer work on any rows that previously had been highlighted. Got all that? Good.
So to get around all that I have a pretty intensive loop that goes through every cell after an update and sets the background color on it according to the color defined for odd and even rows in the CSS (The first time it goes through the list it finds out what the CSS background color should be and stores that so that it can use those values when hard setting the background color). Moral of the story is: Highlighting WILL work and will repect any special CSS styles for table row background colors you have defined but their maybe be a significant performance cost especially if you have a lot of items on this table.
If anyone uses this or tests it on very large datasets let me know how it does (yes I could not be a lackey and test that myself, but help a brotha out :) ). Enjoy!
* rwhite 2/26 : Leave your feedback for future direction here
Posted by Richard White
Wed, 22 Feb 2006 17:36:00 GMT
AjaxScaffold has been deprecated in favor of ActiveScaffold
* rwhite 2/23 – All these issues have been fixed as of version 2.1.0 read more about it here*
I’ve gotten a couple emails about some issues with the Ajax Scaffold Generator, here is the current list I have:
The good news is that I have patch almost all of these in my dev environment and should have a point release out by the end of the week. I’ll try to keep a running list of known issues on the demo page, but in the meantime just leave a comment on this article of any issues you come across.