AjaxScaffold has been deprecated in favour of ActiveScaffold

The aim of this post is to show how to extend or replace the default functionality of the Ajax Scaffold plugin (ASp). I will go over two areas, firstly how you filter the dataset the table displays, and secondly the methods you can override to really gain control.

Simple Filtering of the Dataset

In order to filter the data that the table displays you need to simply override a single method (for each model) in your controller.

conditions_for_{table_name}_collection

This method is expected to return the same array that the Rails find() method accepts as its :conditions parameter.

Lets take a simple user model as an example. The db table has the following columns: id, name, password, employer_id where the employer_id represents a has-one relationship to the user’s employer (represented by another table). Now lets say we only want to see users from the current employer in our table, then all we need to do is define the following method in our controller:

def conditions_for_users_collection
  [ 'employer_id = ?', params[:current_employer] ]
end

This of course assumes that the current request defines :current_employer as the employer’s id.

You can use any conditional statements you like, if they would work in the Rails find() method, they will work here.

More Complex Filtering

At a lower level the collection used by the table is provided by a combination of three methods:

  1. count_{table_name}_collection(model, options)
  2. page_and_sort_{table_name}_collection(model, options, paginator)
  3. page_and_sort_{table_name}_collection_with_method(model, options, paginator)

These methods represent a slightly extended version of the methods found in the Rails paginator. The first two are called for any normal page or sort (i.e not using a ScaffoldColumn defined using the :sort parameter) and the last is called only for ScaffoldColumns defined with, wait for it, the :sort parameter.

For example lets say we have a set of Report objects that are displayed using the following column definitions:

@@scaffold_columns = [
    AjaxScaffold::ScaffoldColumn.new(Report, {
        :name => "title",
        :eval => "row.current_definition.title",
        :sort => 'current_definition.title'}),
    AjaxScaffold::ScaffoldColumn.new(Report, {
        :name => "viewed",
        :eval => "row.views",
        :sort => 'views' }),
]

We also have defined a method that returns the reports for a particular project, or the reports for a project in a particular category (all of which would be difficult to do with a simple :conditions statement):

def get_reports
  project = get_project
  reports = project.reports

  if request.post?
    selected_category = params[:category]
    reports = project.reports_for_category(selected_category) if selected_category
  end
  reports
end

We could then define the three methods above as follows (in ReportsController.rb):

def count_reports_collection(model, options)
  get_reports.size
end

def page_and_sort_reports_collection_with_method(model, options, paginator)
  collection = get_reports
  order_parts = options[:order].split(' ')
  sort_collection_by_method(collection, order_parts[0], order_parts[1]).slice(paginator.current.offset,options[:per_page])
end

def page_and_sort_reports_collection(model, options, paginator)
  page_and_sort_reports_collection_with_method(model, options, paginator)
end

This would cause every sort / page to use the with_method methods, as we need due to all columns using the :sort parameter. Our count would come from our get_reports method and everything should work as expected.

Other Extension Points

Here are some of the other methods that you can override to change the behaviour of the scaffold, its probably a good idea to actually look at the plugin code to see how each method is used, although some are pretty self explanatory.

In all of these {prefix} is defined as {table_name}_.That is the table name with an underscore appended. {suffix} is defined as _{model_name_in_lower_case}. That is the model name in lower case with an underscore prepended. These are only required in multi table scenarios (I have written it like this here to match the actual code). The reason for doing this is to give CRUD like methods when only using a single table.

Default Sort Column

By default the rows are sorted using the primary key, id. To change this you can override: default_sort / default_{prefix}sort

def default_{prefix}sort
   "users.name"
end

Default Sort Direction

To change this from ‘asc’ you can override: default_sort_direction / default_{prefix}sort_direction. The only other possible return value is “desc”.

def default_{prefix}sort_direction
   "desc"
end

Create

If you want to change the default behaviour when a model is created you can override the following method which is called internally:

def do_create#{suffix}
    @user = User.new(params[:user])
    @successful = @user.save
end

Update

If you want to change the default behaviour when a model is updated you can override the following method which is called internally:

def do_update#{suffix}
    @user = User.find(params[:id])
    @successful = @user.update_attributes(params[:user])
end

Table

To add custom behvaiour to the table rendering you can use this method. This is really to add functionality, you still need to call the methods as shown or things may go a little wrong:

def #{prefix}table
    self.#{prefix}table_setup

    OTHER CODE GOES IN HERE

    render#{suffix}_template(:action => 'table')
end

Added in 3.2.2

New

Called before the new form appears

def do_new#{suffix}
  @user = User.new
  @successful = true
end

Edit

Called to find the object to edit

def do_edit#{suffix}
  @user = User.find(params[:id])
  @successful = !@user.nil?
end

Destroy

Called to find and destroy an object

def do_destroy#{suffix}
  @successful = User.find(params[:id]).destroy
end

No Responses to “Extending the Ajax Scaffold Plugin”

  1. Thank you for your helpful tutorial. I’m new to RoR and have found your scaffold plugin very helpful.

    Is there a way to only filter the dataset for a table under certain conditions? I would like to display the table with all data on one page and a subset of the data on another page. I’m using render_component :action => ‘table’. With the filter example, I can get the correct subset but I don’t know how to have the full set sometimes and the subset sometimes.

    Thanks.

  2. Hi Jo, you can just pass parameters in the component call to use in the decision making process:

    render_component :action => ‘table’, :params => params.merge(:filter => ‘all’)

    or something.

    Cheers
    Scott

  3. H,I override the method do_update#{suffix},but there is a exception when I do "edit" option,why?
    thanks.

  4. Hi, I suspect because you are now using "ActiveScaffold":http://www.activescaffold.com. You will need to refer to those docs for customization. The original AjaxScaffold plugin is now deprecated.

    Cheers
    Scott

  5. Does anyone knows how to get FCKEDITOR to be saved to the database while editing in the activescaffold ?
    I’ve used a column overide to load the Fckeditor but it doesn’t allow me to save it to the database.

Sorry, the comment form is closed at this time.