Skip to content
PLAY VIDEO PLAY VIDEO PLAY VIDEO
By Geoff Hodgson

Using ActiveRecord scopes with activeadmin

Activeadmin replaced metasearch with ransack around six months ago (mid-late 2013).

Activeadmin is good.

Ransack is good.

Activeadmin filtering via Ransack, not so good.

It works in the simple cases, but may just suck your will to live for more complicated filters across associations. Here's a simple way to use plain old ActiveRecord scopes instead of having to define custom ransackers.

I'll demonstrate the example with the following models:

class Organisation < ActiveRecord::Base
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :organisation
  has_many :addresses
end

class Address < ActiveRecord::Base
  belongs_to :user
end

A working copy of this example is also available on github.

On the activeadmin page for organisations, we want to be able to filter organisations by address. We can't list every address in a select so we need some kind of text search.

When registering the organisation model, first turn off the filters:

config.filters = false

Next add a filters partial to the sidebar:

sidebar :filters, only: :index do
  render 'admin/organisations/filters'
end

When adding the necessary form elements to this partial to handle the filtering, it is easiest to follow the basic structure (divs, classes, names etc) of the standard activeadmin filters form, so that it follows the same styles. There's just a couple of small gotchas if you render exactly the same form: - Activeadmin expects the filter params to be in a hash with the [:q] key at the top level. If a filter results in no organisations being returned and there isn't a [:q] param in the request, activeadmin will show the message 'No Organisations yet' instead of 'No Organisations found'. A minor issue, easily fixed by either (preferably) building the form with the filter params inside the [:q] hash, or by adding a hidden field to the form that does nothing but ensure activeadmin recognises that filtering is present. - There is an activeadmin form helper (activeadminformfor) that wraps the semanticformfor call with a custom builder, but the custom builder has a few references to ransack, so if you are looking for a way to keep the form clean and terse, you'll probably have to start with semanticform_for.

Next up we override the activeadmin apply_filtering method. Yes, monkey patching is carcinogenic, but we're overriding a method from an engine in the most obvious spot, and it is the recommended way to modify the default behaviour of activeadmin.

Inside the register block:

controller do

  # Override the default apply_filtering method so that we can use AR scopes instead of ransack
  def apply_filtering(chain)
    Organisation.filtering_scopes.each do |scope|
      chain = chain.filter_by(scope, params[scope]) unless params[scope].blank?
    end
    chain
  end

end

Then in the organisation model, define: - the scopes that will perform the filtering - the filterby method to return the scope to be added to the chain - the .filteringscopes method (mostly as a precaution to lock down which methods can be passed through)

class Organisation < ActiveRecord::Base
  ...

  scope :by_name, ->(name) { where('name LIKE ?', "%#{name}%") }
  scope :by_address, ->(address) { joins(users: :addresses)
    .where('addresses.street LIKE ? OR addresses.city LIKE ? OR addresses.state LIKE ?',
     "%#{address}%","%#{address}%","%#{address}%")
  }

  def self.filter_by(filter_type, filter_argument)
    # check if the filter_type is in the allowed filters list,
    # to lock down the send call
    if filtering_scopes.include?(filter_type)
      send("by_#{filter_type}",filter_argument)
    end
  end

  def self.filtering_scopes
    [:name, :address]
  end

  ...
end

And that's it, you're good to go.

Latest Articles by Our Team

Our expert team of designers and developers love what the do and enjoy sharing their knowledge with the world.

We Hire Only the Best

reinteractive is Australia’s largest dedicated Ruby on Rails development company. We don’t cut corners and we know what we are doing.

We are an organisation made up of amazing individuals and we take pride in our team. We are 100% remote work enabling us to choose the best talent no matter which part of the country they live in. reinteractive is dedicated to making it a great place for any developer to work.

Free Community Workshops

We created the Ruby on Rails InstallFest and Ruby on Rails Development Hub to help introduce new people to software development and to help existing developers hone their skills. These workshops provide invaluable mentorship to train developers, addressing key skills shortages in the industry. Software development is a great career choice for all ages and these events help you get started and skilled up.

  • Webinars

    Webinars

    Webinars are our online portal for tips, tricks and lessons learned in everything we do. Make the most of this free resource to help you become a better developer.

    Learn more about webinars

  • Installfest

    Installfest

    The Ruby on Rails Installfest includes a full setup of your development environment and step-by-step instructions on how to build your first app hosted on Heroku. Over 1,800 attendees to date and counting.

    Learn more about Installfest

  • Development Hub

    Development Hub

    The Ruby on Rails Development Hub is a monthly event where you will get the chance to spend time with our team and others in the community to improve and hone your Ruby on Rails skills.

    Learn more about Development Hub

Get the “reinteractive Review” Monthly Email