Repository URL to install this package:
|
Version:
1.0.0.pre ▾
|
module ActiveAdmin
class ResourceController < BaseController
# This module overrides most of the data access methods in Inherited
# Resources to provide Active Admin with it's data.
#
# The module also deals with authorization and resource callbacks.
#
module DataAccess
def self.included(base)
base.class_exec do
include Callbacks
include ScopeChain
define_active_admin_callbacks :build, :create, :update, :save, :destroy
end
end
protected
# Retrieve, memoize and authorize the current collection from the db. This
# method delegates the finding of the collection to #find_collection.
#
# Once #collection has been called, the collection is available using
# either the @collection instance variable or an instance variable named
# after the resource that the collection is for. eg: Post => @post.
#
# @return [ActiveRecord::Relation] The collection for the index
def collection
get_collection_ivar || begin
collection = find_collection
authorize! Authorization::READ, active_admin_config.resource_class
set_collection_ivar collection
end
end
# Does the actual work of retrieving the current collection from the db.
# This is a great method to override if you would like to perform
# some additional db # work before your controller returns and
# authorizes the collection.
#
# @return [ActiveRecord::Relation] The collectin for the index
def find_collection
collection = scoped_collection
collection = apply_authorization_scope(collection)
collection = apply_sorting(collection)
collection = apply_filtering(collection)
collection = apply_scoping(collection)
collection = apply_includes(collection)
unless request.format == 'text/csv'
collection = apply_pagination(collection)
end
collection = apply_collection_decorator(collection)
collection
end
# Override this method in your controllers to modify the start point
# of our searches and index.
#
# This method should return an ActiveRecord::Relation object so that
# the searching and filtering can be applied on top
#
# Note, unless you are doing something special, you should use the
# scope_to method from the Scoping module instead of overriding this
# method.
def scoped_collection
end_of_association_chain
end
# Retrieve, memoize and authorize a resource based on params[:id]. The
# actual work of finding the resource is done in #find_resource.
#
# This method is used on all the member actions:
#
# * show
# * edit
# * update
# * destroy
#
# @return [ActiveRecord::Base] An active record object
def resource
get_resource_ivar || begin
resource = find_resource
authorize_resource! resource
resource = apply_decorator resource
set_resource_ivar resource
end
end
# Does the actual work of finding a resource in the database. This
# method uses the finder method as defined in InheritedResources.
#
# Note that public_send can't be used here because Rails 3.2's
# ActiveRecord::Associations::CollectionProxy (belongs_to associations)
# mysteriously returns an Enumerator object.
#
# @return [ActiveRecord::Base] An active record object.
def find_resource
scoped_collection.send method_for_find, params[:id]
end
# Builds, memoize and authorize a new instance of the resource. The
# actual work of building the new instance is delegated to the
# #build_new_resource method.
#
# This method is used to instantiate and authorize new resources in the
# new and create controller actions.
#
# @return [ActiveRecord::Base] An un-saved active record base object
def build_resource
get_resource_ivar || begin
resource = build_new_resource
run_build_callbacks resource
authorize_resource! resource
resource = apply_decorator resource
set_resource_ivar resource
end
end
# Builds a new resource. This method uses the method_for_build provided
# by Inherited Resources.
#
# Note that public_send can't be used here w/ Rails 3.2 & a belongs_to
# config, or you'll get undefined method `build' for []:Array.
#
# @return [ActiveRecord::Base] An un-saved active record base object
def build_new_resource
scoped_collection.send method_for_build, *resource_params
end
# Calls all the appropriate callbacks and then creates the new resource.
#
# @param [ActiveRecord::Base] object The new resource to create
#
# @return [void]
def create_resource(object)
run_create_callbacks object do
save_resource(object)
end
end
# Calls all the appropriate callbacks and then saves the new resource.
#
# @param [ActiveRecord::Base] object The new resource to save
#
# @return [void]
def save_resource(object)
run_save_callbacks object do
object.save
end
end
# Update an object with the given attributes. Also calls the appropriate
# callbacks for update action.
#
# @param [ActiveRecord::Base] object The instance to update
#
# @param [Array] attributes An array with the attributes in the first position
# and the Active Record "role" in the second. The role
# may be set to nil.
#
# @return [void]
def update_resource(object, attributes)
if object.respond_to?(:assign_attributes)
object.assign_attributes(*attributes)
else
object.attributes = attributes[0]
end
run_update_callbacks object do
save_resource(object)
end
end
# Destroys an object from the database and calls appropriate callbacks.
#
# @return [void]
def destroy_resource(object)
run_destroy_callbacks object do
object.destroy
end
end
#
# Collection Helper Methods
#
# Gives the authorization library a change to pre-scope the collection.
#
# In the case of the CanCan adapter, it calls `#accessible_by` on
# the collection.
#
# @param [ActiveRecord::Relation] collection The collection to scope
#
# @return [ActiveRecord::Relation] a scoped collection of query
def apply_authorization_scope(collection)
action_name = action_to_permission(params[:action])
active_admin_authorization.scope_collection(collection, action_name)
end
def apply_sorting(chain)
params[:order] ||= active_admin_config.sort_order
order_clause = OrderClause.new params[:order]
if order_clause.valid?
chain.reorder(order_clause.to_sql(active_admin_config))
else
chain # just return the chain
end
end
# Applies any Ransack search methods to the currently scoped collection.
# Both `search` and `ransack` are provided, but we use `ransack` to prevent conflicts.
def apply_filtering(chain)
@search = chain.ransack clean_search_params params[:q]
@search.result
end
def clean_search_params(params)
if params.is_a? Hash
params.dup.delete_if{ |key, value| value.blank? }
else
{}
end
end
def apply_scoping(chain)
@collection_before_scope = chain
if current_scope
scope_chain(current_scope, chain)
else
chain
end
end
def apply_includes(chain)
if active_admin_config.includes.any?
chain.includes *active_admin_config.includes
else
chain
end
end
def collection_before_scope
@collection_before_scope
end
def current_scope
@current_scope ||= if params[:scope]
active_admin_config.get_scope_by_id(params[:scope])
else
active_admin_config.default_scope(self)
end
end
def apply_pagination(chain)
page_method_name = Kaminari.config.page_method_name
page = params[Kaminari.config.param_name]
chain.public_send(page_method_name, page).per(per_page)
end
def per_page
if active_admin_config.paginate
dynamic_per_page || configured_per_page
else
max_per_page
end
end
def dynamic_per_page
params[:per_page] || @per_page
end
def configured_per_page
if active_admin_config.per_page.is_a?(Array)
active_admin_config.per_page[0]
else
active_admin_config.per_page
end
end
def max_per_page
10_000
end
end
end
end