require "typus/format"
class Admin::ResourcesController < Admin::BaseController
include Typus::Format
before_filter :get_model
before_filter :get_object,
:only => [ :show,
:edit, :update, :destroy, :toggle,
:position, :relate, :unrelate,
:detach ]
before_filter :check_resource_ownership,
:only => [ :edit, :update, :destroy, :toggle,
:position, :relate, :unrelate ]
before_filter :check_if_user_can_perform_action_on_user,
:only => [ :edit, :update, :toggle, :destroy ]
before_filter :check_if_user_can_perform_action_on_resources
before_filter :set_order,
:only => [ :index ]
before_filter :set_fields,
:only => [ :index, :new, :edit, :create, :update, :show ]
##
# This is the main index of the model. With filters, conditions
# and more.
#
# By default application can respond_to html, csv and xml, but you
# can add your formats.
#
def index
@conditions, @joins = @resource.build_conditions(params)
check_resource_ownerships if @resource.typus_options_for(:only_user_items)
respond_to do |format|
format.html { generate_html and select_template }
@resource.typus_export_formats.each { |f| format.send(f) { send("generate_#{f}") } }
end
end
def new
check_ownership_of_referal_item
item_params = params.dup
rejections = %w( controller action resource resource_id back_to selected )
item_params.delete_if { |k, v| rejections.include?(k) }
@item = @resource.new(item_params)
select_template
end
##
# Create new items. There's an special case when we create an
# item from another item. In this case, after the item is
# created we also create the relationship between these items.
#
def create
@item = @resource.new(params[@object_name])
set_attributes_on_create
if @item.valid?
create_with_back_to and return if params[:back_to]
@item.save
redirect_on_success
else
select_template(:new)
end
end
def edit
select_template
end
def show
check_resource_ownership and return if @resource.typus_options_for(:only_user_items)
select_template
end
def update
if @item.update_attributes(params[@object_name])
set_attributes_on_update
reload_locales
redirect_on_success
else
select_template(:edit)
end
end
def destroy
@item.destroy
notice = _("%{model} successfully removed.", :model => @resource.model_name.human)
redirect_to set_path, :notice => notice
end
def toggle
@item.toggle(params[:field])
@item.save!
notice = _("%{model} %{attribute} changed.",
:model => @resource.model_name.human,
:attribute => params[:field].humanize.downcase)
redirect_to set_path, :notice => notice
end
##
# Change item position. This only works if acts_as_list is
# installed. We can then move items:
#
# params[:go] = 'move_to_top'
#
# Available positions are move_to_top, move_higher, move_lower,
# move_to_bottom.
#
def position
@item.send(params[:go])
notice = _("Record moved %{to}.", :to => params[:go].gsub(/move_/, '').humanize.downcase)
redirect_to set_path, :notice => notice
end
##
# Relate a model object to another, this action is used only by the
# has_and_belongs_to_many and has_many relationships.
#
def relate
resource_class = params[:related][:model].constantize
resource_tableized = params[:related][:model].tableize
if @item.send(resource_tableized) << resource_class.find(params[:related][:id])
flash[:notice] = _("%{model_a} related to %{model_b}",
:model_a => resource_class.model_name.human,
:model_b => @resource.model_name.human)
else
flash[:alert] = _("%{model_a} cannot be related to %{model_b}",
:model_a => resource_class.model_name.human,
:model_b => @resource.model_name.human)
end
redirect_to set_path
end
##
# Remove relationship between models, this action never removes items!
#
def unrelate
resource_class = params[:resource].classify.constantize
resource_tableized = params[:resource].tableize
resource = resource_class.find(params[:resource_id])
# We consider that we are unrelating a has_many or has_and_belongs_to_many
macro = @resource.reflect_on_association(resource_class.table_name.to_sym).try(:macro)
case macro
# when :has_one
# attribute = resource_tableized.singularize
# saved_succesfully = @item.update_attribute attribute, nil
when :has_many
##
# We have to verify we can unrelate. For example: A Category which
# has many posts and Post validates_presence_of Category should not
# be removed.
#
attribute = @resource.table_name.singularize
saved_succesfully = resource.update_attributes(attribute => nil)
when :has_and_belongs_to_many
attribute = resource_tableized
saved_succesfully = @item.send(attribute).delete(resource)
else
saved_succesfully = false
end
if saved_succesfully
flash[:notice] = _("%{model_a} unrelated from %{model_b}",
:model_a => resource_class.model_name.human,
:model_b => @resource.model_name.human)
else
flash[:alert] = _("%{model_a} cannot be unrelated from %{model_b}",
:model_a => resource_class.model_name.human,
:model_b => @resource.model_name.human)
end
redirect_to set_path
end
##
# Remove file attachments.
#
def detach
message = if @item.update_attributes(params[:attachment] => nil)
"%{attachment} removed."
else
"%{attachment} can't be removed."
end
attachment = @resource.human_attribute_name(params[:attachment])
notice = _(message, :attachment => attachment)
redirect_to set_path, :notice => notice
end
private
def get_model
@resource = params[:controller].extract_class
@object_name = ActiveModel::Naming.singular(@resource)
end
##
# Find model when performing an edit, update, destroy, relate,
# unrelate ...
#
def get_object
@item = @resource.find(params[:id])
end
def set_fields
mapping = case params[:action]
when "index" then :list
when "new", "edit", "create", "update" then :form
else params[:action]
end
@fields = @resource.typus_fields_for(mapping)
end
def set_order
params[:sort_order] ||= "desc"
@order = params[:order_by] ? "#{@resource.table_name}.#{params[:order_by]} #{params[:sort_order]}" : @resource.typus_order_by
end
def redirect_on_success
action = @resource.typus_options_for(:action_after_save)
case params[:action]
when "create"
path = { :action => action }
path.merge!(:id => @item.id) unless action.eql?("index")
notice = _("%{model} successfully created.", :model => @resource.model_name.human)
when "update"
path = case action
when "index"
params[:back_to] ? "#{params[:back_to]}##{@resource.to_resource}" : { :action => action }
else
{ :action => action,
:id => @item.id,
:back_to => params[:back_to] }
end
notice = _("%{model} successfully updated.", :model => @resource.model_name.human)
end
redirect_to path, :notice => notice
end
##
# When params[:back_to] is defined this action is used.
#
# - has_and_belongs_to_many relationships.
# - has_many relationships (polymorphic ones).
#
def create_with_back_to
if params[:resource] && params[:resource_id]
resource_class = params[:resource].classify.constantize
resource_id = params[:resource_id]
resource = resource_class.find(resource_id)
association = @resource.reflect_on_association(params[:resource].to_sym).macro rescue :polymorphic
else
association = :has_many
end
case association
when :belongs_to
@item.save
when :has_and_belongs_to_many
@item.save
@item.send(params[:resource]) << resource
when :has_many
@item.save
message = _("%{model} successfully created.", :model => @resource.model_name.human)
path = "#{params[:back_to]}?#{params[:selected]}=#{@item.id}"
when :polymorphic
resource.send(@item.class.to_resource).create(params[@object_name])
end
flash[:notice] = message || _("%{model_a} successfully assigned to %{model_b}.",
:model_a => @item.class.model_name.human,
:model_b => resource_class.model_name.human)
redirect_to path || params[:back_to]
end
def select_template(template = params[:action], resource = @resource.to_resource)
folder = (File.exist?("app/views/admin/#{resource}/#{template}.html.erb")) ? resource : 'resources'
render "admin/#{folder}/#{template}"
end
end