Adding custom filters on active admin using Ransacker

Scenario for below code…
Customer placing orders for a several line items of a vendor in a shopping website..
Tables : Order (has many line items)
line item (belongs to vendor)

Following is the code for filter by vendor on order’s page (Note: order table is not directly related with vendor, there can be multiple vendors involved on a single order. Order table does not have vendor_id and similarly vendor table not having order_id. But line_items table have order_id and vendor_id stored, so this needs to customized at it’s best)

app/admin/order.rb
filter :vendor_in,
:as => :select,
:label => ‘Vendor’,
:collection => proc { Vendor.all.map{ |vendor| [vendor.username, user.id] }.uniq }

app/models/order.rb
ransacker :vendor,
formatter: proc { |selected_vendor_id|
results = Order.has_vendor(selected_vendor_id).map(&:id)
results = results.present? ? results : nil
}, splat_params: true do |parent|
parent.table[:id]
end

# Executes the query which fetches the orders of selected vendor
def self.has_vendor(vendor_id)
self.joins(:line_items).where(“line_items.vendor_id = ?”, vendor_id).uniq
end

That’s it you are done!

Angular JS implementation with Rails 4

Step 1 : Create rails app using rails new employee_details
Step 2 : Remove turbolinks gem from gemfile and add ‘pg’ gem for postgres. Set the rails version to 4.1.2 (Turbolinks may not work with angular js)
Step 3 : Run bundle install
Step 4 : Change database.yml to use postgres
development:
adapter: postgresql
encoding: unicode
database: employee_details
username: postgres
password: root
pool: 100
Step 5 : Create the model
rails g model EmployeeDetail employee_id:integer employee_name:string expertise:string experience:integer education:string mobile:string address:text gender:boolean
Step 6 : Run rake db:create and rake db:migrate
Step 7 : Create a controller
rails g controller employee_details
class EmployeeDetailsController < ApplicationController
def index
end
end
Step 8 : Create a view file for employee_details
<div>
<h1>Ruby on Rails Rocks</h1>
</div>
Step 9 : Add routes for index page
root ’employee_details#index’
Step 10 : Change layout file, remove turbolinks, add ng-app with the app name and point angular javascripts
<!DOCTYPE html>
<html ng-app=”EmployeeDetails”>
<head>
<title>Employee Details</title>
<%= stylesheet_link_tag ‘application’, media: ‘all’ %>
<%= csrf_meta_tags %>
</head>
<body>
<header>
Angular
</header>

<%= yield %>
<script src=”//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js”></script>
<script src=”//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular-resource.min.js”></script>
<%= javascript_include_tag “application” %>

</body>
</html>
Step 11 : change assets/javascripts/application.js
//
//= require app
//= require_tree ./../angular
Step 12 : Define app which we referred above in app.js.coffee
window.App = angular.module(‘EmployeeDetails’, [‘ngResource’])
Step 13 : Define custom routes
EmployeeDetails::Application.routes.draw do
root ’employee_details#index’
end
Step 14 : Create directories as below
assets/angular
assets/angular/controllers
assets/angular/services
assets/angular/directives
Running the app now should display ‘Ruby on Rails Rocks’
Step 15 : Change the index.html to below
<div ng-controller=”EmployeeDetailsCtrl”>
<h1>Message: {{title}}</h1>
</div>
Step 16 : Now create the angular controller (inside assets/angular/controllers/employeedetailsCtrl.js.coffee) referred above and assign title
App.controller ‘EmployeeDetailsCtrl’, [‘$scope’, ($scope) ->
$scope.title = “Ruby on Rails Always Rocks!”
]
Restart the server. Running the app now should display ‘Ruby on Rails Always Rocks’
Step 17 : Change the index method of controller and render json
class EmployeeDetailsController < ApplicationController
def index
render json: EmployeeDetail.all
end
end
Step 18 : Generate few records using seed
#Emp ID, Emp Name, Expertise, Experience, Education, Mobile, Address, Gender
employees = EmployeeDetail.all.count
if employees == 0
employee_id = [101,102,103,104,105]
employee_name = [“Arun”, “Kumar”, “Raja”, “Karthik”, “Surya”]
expertise = [“RubyOnRails”, “English Literature”, “PhP”, “Admin”, “Java”]
experience = [5,4,3,4,5]
education = [“M.C.A”, “M.A”, “B.E”, “B.E”, “B.E”]
mobile = [“9987656478”, “9878965437”,”9786587987″, “9879547897”, “9876096543”]
address = [“Chennai”, “Madurai”, “US”, “Cuddalore”, “Trivandrum”]
gender = [0,1,1,0,0]
for i in 0..4
EmployeeDetail.create(
employee_id: employee_id[i], employee_name: employee_name[i],
expertise: expertise[i], experience: experience[i],
education: education[i], mobile: mobile[i],
address: address[i], gender: gender[i]
)
end
end
Step 19 : Run rake db:seed
Now go and run the app, you should see the records in JSON format.
Step 20 : Create the home controller (we will be using this controller for angular implementation)
class HomeController < ApplicationController
def index
end
end
Step 21 : Apply root to home controller index method and create api routes for angular
scope :api do
get “/employee_details(.:format)” => “employee_details#index”
get “/employee_details/:id(.:format)” => “employee_details#show”
end
root ‘home#index’
Step 22 : Get the records on angular controller
App.controller ‘EmployeeDetailsCtrl’, [‘$scope’, ‘EmployeeDetail’, ($scope, EmployeeDetail) ->
$scope.showEmployeeDetail = null
$scope.selectedRow = null

$scope.employee_details = EmployeeDetail.query ->
$scope.showEmployeeDetail = $scope.employee_details[0]
$scope.selectedRow = 0

$scope.showEmployeeDetail = (employee, row) ->
$scope.showEmployeeDetail = employee
$scope.selectedRow = row
]
Step 23 : Create the service for api
App.factory ‘EmployeeDetail’, [‘$resource’, ($resource) ->
$resource ‘/api/employee_details/:id’, id: ‘@id’
]

Step 24 : Now change the view file for listing employees (app/views/home/index.html.erb)
<div ng-controller=”EmployeeDetailsCtrl”>
<ul>
<h1>{{title}}</h1>
<li ng-repeat=”employee in employee_details”>
<h3>{{employee.employee_id}} <small>({{employee.employee_name}})</small></h3>
</li>
</ul>
<div ng-show=”showEmployeeDetail”>
<h2>{{showEmployeeDetail.employee_id}}</h2>
<p>{{showEmployeeDetail.employee_name}}</p>
<p>
Expertise : {{showEmployeeDetail.expertise}}
</p>
</div>
</div>

 

Restart the server. Executing the application at http://localhost:3000 will now display the list of employees and the information of first employee.