Skip to content

Custom Association Options

activescaffold edited this page Sep 3, 2012 · 17 revisions

When ActiveScaffold displays a dropdown on the form of records to associate with the current record (the one being edited or created), it has to decide which records should be present. The default behavior is to display “orphaned” (unassociated) records for :has_one and :has_many associations, and to display all records for :belongs_to and :has_and_belongs_to_many, sorted by to_label method.

You may want to display all records every time, or you may want to impose extra conditions. The solution is to create a method called options_for_association_conditions in your controller’s helper file. This method accepts an AssociationReflection object and returns SQL conditions (in any of the common formats).

This method is used in association columns with :select form_ui too.

For example, let’s say that you have a UsersController, and that a User has_and_belongs_to_many Roles. Let’s say that you don’t want to show the Admin Role as an option, unless the current user is an Admin. You’ve already got validation set up, but you just don’t want the option in the list. Here’s what you could do:

module UsersHelper
  def options_for_association_conditions(association)
    if association.name == :role
      ['roles.id != ?', Role.find_by_name('admin').id] unless current_user.admin?
    else
      super
    end
  end
end

Remember that, since this method is a view helper, you can access all the associated controller and views associated methods and variables, including the params; given this, you can easily access the record being edited in the @record variable:

class UsersController < ApplicationController
  active_scaffold do |config|
    config.columns[:author].form_ui = :select
    config.columns[:author].update_columns = :book
    config.columns[:book].form_ui = :select
  end
end

module UsersHelper
  def options_for_association_conditions(association)
    if association.name == :book
      {'books.author_id' => @record.author_id}
    else
      super
    end
  end
end

If you want to use scopes to get the associated records, you must override association_options_find method in your controller’s helper file. This method gets the AssociationReflection object and a optional conditions argument. You can invoke super and pass a block, the parent method will invoke the block with the relation so you can invoke scope methods in it.

class User < ActiveRecord::Base
  scope :with_role, lambda { |role| where(:role => role) }
end

module UsersHelper
  def association_options_find(association)
    if association.name == :role
      super { |relation| relation.with_role('admin') }
    else
      super
    end
  end
end
Clone this wiki locally