Activeadmin: 4 steps to add auto complete in ActiveAdmin

Created on 4 Nov 2012  路  32Comments  路  Source: activeadmin/activeadmin

Actually this is not an issue, but a tips for ActiveAdmin users which need autocomplete functional.
OK here we go.

Take adding autocomple for email column of admin_user model as an example.

  1. add gem "rails3-jquery-autocomplete"
  2. set reqruied js in app/assets/javascripts/active_admin.js:
//= require autocomplete-rails
  1. add autocomplete routes and action in app/admin/admin_user.rb (for example):

    # define routes for "autocomplete :admin_user, :email"
    collection_action :autocomplete_admin_user_email, :method => :get
    
    controller do
       autocomplete :admin_user, :email
    end
    
  2. set input as :autocomplete type and url for ajax
f.input :email, :as => :autocomplete, :url => autocomplete_admin_user_email_admin_admin_users_path

How to apply autocomplete for "filter"?

# make "filter :email" can autocomplete
filter :email_contains, :as => :autocomplete, :url => '/admin/admin_users/autocomplete_admin_user_email',
                        :label => "Search Email", :required => false,
                        :wrapper_html => { :style => "list-style: none" }
documentation

Most helpful comment

Solution to a few of the issues (templates missing, JS conflict, $().autocomplete missing)

Stack

Rails 4.2.1
ActiveAdmin 1.0.0.pre1 0b4b228

Gemfile

gem 'jquery-rails'
gem 'rails-jquery-autocomplete' # This is the maintained version of rails3-jquery-autocomplete

active_admin.js.coffee

#= require active_admin/base
#= require jquery-ui/autocomplete

config/active_admin.rb

I had to add a JS include to make Heroku play nice.

config.register_javascript 'autocomplete-rails.js'

autocomplete-rails.js generated from plugin, gisted here for ease of use

admin/partner.rb

In my case, I have an Order model that belongs_to a Partner. So, I want to autocomplete order.partner_id

  collection_action :autocomplete_partner_name, :method => :get

  controller do
    autocomplete :partner, :name, :full => true
  end

admin/order.rb

In my form I have:

 f.input :partner_name, :as => :autocomplete,
        :url => autocomplete_partner_name_admin_partners_path,
        :input_html => {:id_element => '#order_partner_id',
                        'data-auto-focus' => true,
                        value: order.new_record? && params[:partner_id].present? ? Partner.find_by_id(params[:partner_id]).try(:name) : order.partner_name}

        f.input :partner_id, :as => :hidden, :input_html => {value: order.new_record? && params[:partner_id].present? ? params[:partner_id] : order.partner_id}

models/order.rb

I needed to be able to pull the Partner#name field when editing an order,
so I made an accessor / memoized getter/setter

  attr_accessor :partner_name # for autocomplete
  def partner_name
    @partner_name ||= self.try(:partner).try(:name)
    return @partner_name
  end

stylesheets/active_admin.css.scss

The CSS gets messed up too, so I pasted in the bootstrap overrides and matched
the DOM classes

.ui-autocomplete {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1000;
    float: left;
    display: none;
    min-width: 160px;
    padding: 4px 0;
    margin: 0 0 10px 25px;
    list-style: none;
    background-color: #ffffff;
    border-color: #ccc;
    border-color: rgba(0, 0, 0, 0.2);
    border-style: solid;
    border-width: 1px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;
    -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
    -webkit-background-clip: padding-box;
    -moz-background-clip: padding;
    background-clip: padding-box;
    *border-right-width: 2px;
    *border-bottom-width: 2px;
}

.ui-menu-item > a.ui-corner-all {
    display: block;
    padding: 3px 15px;
    clear: both;
    font-weight: normal;
    line-height: 18px;
    color: #555555;
    white-space: nowrap;
    text-decoration: none;
}

.ui-state-hover, .ui-state-focus {
    color: #fff;
    text-decoration: none;
    background-color: #3db1ff;
    border-radius: 0px;
    -webkit-border-radius: 0px;
    -moz-border-radius: 0px;
    background-image: none;
}

All 32 comments

@rainchen Thanks for the tip. Could you add it to the wiki section of ActiveAdmin?

which section? "Other" ?

Hmm... following this steps I get a template missing error. If I set up the routing manually it works.

  namespace :admin do
    resources :admin_users do
      get :autocomplete_admin_user_email, :on => :collection
    end
  end

@jan0sch
weird, which version you are using?
This https://gist.github.com/4083276 is the full code I'm using in a live project with activeadmin 0.5.0.

I'm using rails 3.2.8 and activeadmin 0.5.0. The only difference I can see from your code is that I have some cancan stuff (load_and_authorize_resource) in the controller.

@jan0sch
I tried integrated cancan following https://github.com/gregbell/active_admin/wiki/How-to-work-with-cancan. Everything works fine. Maybe it's not cancan's problem.

I'll try it on a clean application when there is time. Right now only have the problem on a rather large application which startet on activeadmin 0.4 and was recently upgraded to 0.5. So maybe the problem is rooted deeper.

Anyway thanks for your steps, they saved a lot of time for me.

It's a shame this is not anymore a solution if you use jquery > 1.9.0. See this bug from the gem "rails3-jquery-autocomplete"

Can this autocomplete be used in forms with belongs_to field?

So far, I can't find how to do it.

Have the same issue with template missing error. Manual adding route doesn't help.

I am getting this error

undefined method `email_contains' for #MetaSearch::Searches::Product:0xcf30280

email_contains is for User model as example, please change it to #{attr}_contains for your model.

If anyone needs to add support to associations and scoping to current user:

class Post < ActiveRecord::Base
  search_methods :post_tag
end

ActiveAdmin.register Tag do
  collection_action :autocomplete_tag_name, :method => :get

  controller do
    autocomplete :tag, :name

    # http://stackoverflow.com/questions/7244515/rails-gem-rails3-jquery-autocomplete-how-to-scope-by-user
    def get_autocomplete_items(parameters)
      items = super(parameters)
      items = items.where(:user_id => current_admin_user.id)
    end
  end
end

ActiveAdmin.register Post do
  filter :tag_name_contains, :as => :autocomplete, 
          :url => '/admin/categories/autocomplete_tag_name', 
          :label => "Tag", :required => false, 
          :wrapper_html => {:style => "list-style: none"}
end

The route and everything is working for me, except the GET always returns 404.
GET http://lvh.me/admin/brand/autocomplete_brand_name?term=office 404 (Not Found)
I have a brand named "office depot"

I found it very interesting that I had to declare collection_action brfore controller block. Otherwise you get a missing template error.

If you're wondering why the styling is broken, don't forget to require jquery.ui.autocomplete in your css.

I get a missing template error

@josespinal Solution worked great and I had the autocomplete values in a separate model.
To everyone : Just follow @josepinal's solution above exactly, replacing your model/field names
Just two caveats after that:
1) make sure you add jquery to active_admin.js if you have not included active_admin in application.js
_#= require jquery_
_#= require jquery_ujs_
_#= require jquery.ui.all_

2) If you get _NoMethodError (undefined method `id' for "placeholder value":String)_
remember to only return the actual _model(s)_ from _get_autocomplete_items_ method and _not_ the actual String value of the model field that is being autocompleted

Is this valid for rails 4?

What is the solution for the template missing error?

@stacia did you find a solution to the template missing error?

Same error with template

To use autocomplete in ActiveAdmin filters, newer versions of activeadmin seem to require a wrapper to the Formtastic input provided by Rails3-jquery-autocomplete, i.e., ActiveAdmin::Inputs::FilterAutocompleteInput. Drop this in your initializers:

module ActiveAdmin
  module Inputs
    class FilterAutocompleteInput < ::Formtastic::Inputs::AutocompleteInput
      include FilterBase
      include FilterBase::SearchMethodSelect

      # The field name in the filter should be field_name_eq or field_name_contains, eg:
      #  filter :user_full_name_eq, as: :autocomplete, url: '/admin/users/autocomplete_user_full_name', label: 'User name (autocomplete)', required: false, wrapper_html: {style: 'list-style: none'}

      def to_html
        input_wrapping do
          label_html <<
          builder.autocomplete_field(method, options.delete(:url), input_html_options)
        end
      end

    end
  end
end

I get the missing template error when the autocomplete :tag, :name part is in the wrong controller. I believe if you put it in the controller of the resource that's being queried (which is not necessarily the same controller as the one that's handling the form), that'll fix the template error.

Here's an updated version of the previous code block, for AA 1.0.0.pre1, to add an autocomplete type to AA filters. For Rails 4 I'm using the 'rails-jquery-autocomplete' gem (https://github.com/crowdint/rails3-jquery-autocomplete).

# For autocomplete filters
module ActiveAdmin
  module Inputs
    class FilterAutocompleteInput < ::Formtastic::Inputs::AutocompleteInput
      include ActiveAdmin::Inputs::Filters::Base

      def input_name
        "#{super}_eq"
      end

      def extra_input_html_options
        {}
      end
    end
  end
end

Solution to a few of the issues (templates missing, JS conflict, $().autocomplete missing)

Stack

Rails 4.2.1
ActiveAdmin 1.0.0.pre1 0b4b228

Gemfile

gem 'jquery-rails'
gem 'rails-jquery-autocomplete' # This is the maintained version of rails3-jquery-autocomplete

active_admin.js.coffee

#= require active_admin/base
#= require jquery-ui/autocomplete

config/active_admin.rb

I had to add a JS include to make Heroku play nice.

config.register_javascript 'autocomplete-rails.js'

autocomplete-rails.js generated from plugin, gisted here for ease of use

admin/partner.rb

In my case, I have an Order model that belongs_to a Partner. So, I want to autocomplete order.partner_id

  collection_action :autocomplete_partner_name, :method => :get

  controller do
    autocomplete :partner, :name, :full => true
  end

admin/order.rb

In my form I have:

 f.input :partner_name, :as => :autocomplete,
        :url => autocomplete_partner_name_admin_partners_path,
        :input_html => {:id_element => '#order_partner_id',
                        'data-auto-focus' => true,
                        value: order.new_record? && params[:partner_id].present? ? Partner.find_by_id(params[:partner_id]).try(:name) : order.partner_name}

        f.input :partner_id, :as => :hidden, :input_html => {value: order.new_record? && params[:partner_id].present? ? params[:partner_id] : order.partner_id}

models/order.rb

I needed to be able to pull the Partner#name field when editing an order,
so I made an accessor / memoized getter/setter

  attr_accessor :partner_name # for autocomplete
  def partner_name
    @partner_name ||= self.try(:partner).try(:name)
    return @partner_name
  end

stylesheets/active_admin.css.scss

The CSS gets messed up too, so I pasted in the bootstrap overrides and matched
the DOM classes

.ui-autocomplete {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1000;
    float: left;
    display: none;
    min-width: 160px;
    padding: 4px 0;
    margin: 0 0 10px 25px;
    list-style: none;
    background-color: #ffffff;
    border-color: #ccc;
    border-color: rgba(0, 0, 0, 0.2);
    border-style: solid;
    border-width: 1px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;
    -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
    -webkit-background-clip: padding-box;
    -moz-background-clip: padding;
    background-clip: padding-box;
    *border-right-width: 2px;
    *border-bottom-width: 2px;
}

.ui-menu-item > a.ui-corner-all {
    display: block;
    padding: 3px 15px;
    clear: both;
    font-weight: normal;
    line-height: 18px;
    color: #555555;
    white-space: nowrap;
    text-decoration: none;
}

.ui-state-hover, .ui-state-focus {
    color: #fff;
    text-decoration: none;
    background-color: #3db1ff;
    border-radius: 0px;
    -webkit-border-radius: 0px;
    -moz-border-radius: 0px;
    background-image: none;
}

@mikelarkin Your solution works like a charm, but the values don't appear when you edit the record.

@iamrahulroy Sorry for the delay...it works for me when I edit. Happy to help debug if needed, just message me.

@mikelarkin It's fine. It's been more than 2 months. Even I don't remember what was the real issue. Thanks for the response, though!

Anyway we could integrate with this: https://gist.github.com/tylerhunt/8058321
I just try this method on rails 5 and got
undefined method company' for #<Ransack::Search:0x0056472c080510>
`

edit: fixed (removed) link markup

Tried, it's not working with has_many through.

@truongnmt What do you mean by the link markup?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

simontol picture simontol  路  28Comments

subhashb picture subhashb  路  60Comments

seanlinsley picture seanlinsley  路  55Comments

robotmay picture robotmay  路  61Comments

ghost picture ghost  路  63Comments