require 'csv'
module Alchemy
module Admin
class ResourcesController < Alchemy::Admin::BaseController
include Alchemy::ResourcesHelper
helper Alchemy::ResourcesHelper
helper_method :resource_handler
before_filter :load_resource, :only => [:show, :edit, :update, :destroy]
handles_sortable_columns do |c|
c.default_sort_value = :name
c.link_class = 'sortable'
c.indicator_class = {:asc => "sorted asc", :desc => "sorted desc"}
c.indicator_text = {:asc => " ↓ ", :desc => " ↑ "}
end
def index
items = resource_handler.model
if contains_relations?
items = items.includes(*resource_relations_names)
end
if params[:query].present?
items = query_items(items)
end
items = items.order(sort_order)
respond_to do |format|
format.html {
items = items.page(params[:page] || 1).per(per_page_value_for_screen_size)
instance_variable_set("@#{resource_handler.resources_name}", items)
}
format.csv {
instance_variable_set("@#{resource_handler.resources_name}", items)
}
end
end
def new
instance_variable_set("@#{resource_handler.resource_name}", resource_handler.model.new)
render :layout => !request.xhr?
end
def show
render action: 'edit', layout: !request.xhr?
end
def edit
render :layout => !request.xhr?
end
def create
instance_variable_set("@#{resource_handler.resource_name}", resource_handler.model.new(params[resource_handler.namespaced_resource_name.to_sym]))
resource_instance_variable.save
render_errors_or_redirect(
resource_instance_variable,
resources_path,
flash_notice_for_resource_action
)
end
def update
resource_instance_variable.update_attributes(params[resource_handler.namespaced_resource_name.to_sym])
render_errors_or_redirect(
resource_instance_variable,
resources_path,
flash_notice_for_resource_action
)
end
def destroy
resource_instance_variable.destroy
flash_notice_for_resource_action
end
def resource_handler
@_resource_handler ||= Alchemy::Resource.new(controller_path, alchemy_module)
end
protected
# Returns a translated +flash[:notice]+.
# The key should look like "Modelname successfully created|updated|destroyed."
def flash_notice_for_resource_action(action = params[:action])
return if resource_instance_variable.errors.any?
case action.to_sym
when :create
verb = "created"
when :update
verb = "updated"
when :destroy
verb = "removed"
end
flash[:notice] = _t("#{resource_handler.resource_name.classify} successfully #{verb}", :default => _t("Succesfully #{verb}"))
end
def is_alchemy_module?
not alchemy_module.nil? and not alchemy_module['engine_name'].nil?
end
def alchemy_module
@alchemy_module ||= module_definition_for(:controller => params[:controller], :action => 'index')
end
def load_resource
instance_variable_set("@#{resource_handler.resource_name}", resource_handler.model.find(params[:id]))
end
# Returns a sort order for AR#sort method
#
# Falls back to fallback_sort_order, if the requested column is not a column of model.
#
# If the column is a tablename and column combination that matches any resource relations, than this order will be taken.
#
def sort_order
sortable_column_order do |column, direction|
if resource_handler.model_associations.present? && column.match(/\./)
table, column = column.split('.')
if resource_handler.model_associations.detect { |a| a.table_name == table }
"#{table}.#{column} #{direction}"
else
fallback_sort_order(direction)
end
elsif resource_handler.model.column_names.include?(column.to_s)
"#{resource_handler.model.table_name}.#{column} #{direction}"
else
fallback_sort_order(direction)
end
end
end
# Default sort order fallback
#
# Overwrite this in your controller to define custom fallback
#
def fallback_sort_order(direction)
"#{resource_handler.model.table_name}.id #{direction}"
end
# Returns an activerecord object that contains items matching params[:query]
#
def query_items(items)
query = params[:query].downcase.split(' ').join('%')
query = ActiveRecord::Base.sanitize("%#{query}%")
items.where(search_query(query))
end
# Returns a search query string
#
# It queries all searchable attributes from resource model via LIKE and joins them via OR.
#
# If the attribute is a relation it builds the query for the associated table.
#
def search_query(search_terms)
resource_handler.searchable_attributes.map do |attribute|
if relation = attribute[:relation]
"#{relation[:model_association].klass.table_name}.#{relation[:attr_method]} LIKE #{search_terms}"
else
"#{resource_handler.model.table_name}.#{attribute[:name]} LIKE #{search_terms}"
end
end.join(" OR ")
end
end
end
end