alexandre025/cdx

View on GitHub
app/controllers/cdx/admin/resource_controller.rb

Summary

Maintainability
B
4 hrs
Test Coverage
module Cdx
  module Admin
    class ResourceController < BaseController
      before_action :authenticate_admin_user!

      before_action :load_resource

      before_action :authorize_admin

      helper_method :member_action?, :new_object_url, :edit_object_url, :object_url, :collection_url, :parent_collection_url, :parent_object_url, :edit_parent_object_url

      def index
        @collection = @collection.page(params[:page])
      end

      def new
      end

      def edit
      end

      def update
        if @object.update permitted_resource_params
          flash_message(@object, :update, :success)
          redirect_to location_after_save
        else
          flash_message(@object, :update, :error)
          render :edit
        end
      end

      def create
        if @object.update permitted_resource_params
          flash_message(@object, :create, :success)
          redirect_to location_after_save
        else
          flash_message(@object, :create, :error)
          render :new
        end
      end

      def destroy
        if @object.destroy
          flash_message(@object, :destroy, :success)
        else
          flash_message(@object, :destroy, :error)
        end

        redirect_to location_after_destroy
      end

      protected

        class << self
          attr_accessor :parent_data

          def belongs_to(model_name, options = {})
            @parent_data ||= {}
            @parent_data[:model_name]  = model_name
            @parent_data[:model_class] = model_name.to_s.classify.constantize
            @parent_data[:find_by]     = options[:find_by] || :id
          end
        end

        # Allow all attributes to be updatable.
        #
        # Other controllers can, should, override it to set custom logic
        def permitted_resource_params
          params[resource.object_name].present? ? params.require(resource.object_name).permit! : ActionController::Parameters.new
        end

        def load_resource
          if member_action? # Load member action
            @object ||= load_resource_instance
            authorize! action, @object
            instance_variable_set("@#{resource.object_name}", @object)
          else # Load collection
            @collection ||= collection
            instance_variable_set("@#{controller_name}", @collection)
          end
        end

        def collection
          return parent.send(controller_name) if parent_data.present?
          if model_class.respond_to?(:accessible_by)
            model_class.accessible_by(current_ability, action)
          else
            model_class.where(nil)
          end
        end

        def resource
          return @resource if @resource
          parent_model_name = parent_data[:model_name] if parent_data
          @resource         = Cdx::Admin::Resource.new controller_path, controller_name, parent_model_name, object_name
        end

        def load_resource_instance
          if new_actions.include? action
            build_resource
          elsif params[:id]
            find_resource
          end
        end

        def build_resource
          if parent_data.present?
            parent.send(controller_name).build
          else
            # This line should be overridden when custom resource initializer is needed
            model_class.new
          end
        end

        def find_resource
          if parent_data.present?
            parent.send(controller_name).find(params[:id])
          else
            model_class.respond_to?(:friendly) ? model_class.friendly.find(params[:id]) : model_class.find(params[:id])
          end
        end

        def parent_data
          self.class.parent_data
        end

        def parent
          if parent_data.present?
            @parent ||= parent_data[:model_class].send(:find_by, parent_data[:find_by].to_s => params["#{resource.model_name}_id"])
            instance_variable_set("@#{resource.model_name}", @parent)
          else
            nil
          end
        end

        def model_class
          @model_class ||= resource.model_class
        end

        # This method should be overridden when object_name does not match the controller name
        def object_name
        end

        def collection_actions
          [:index]
        end

        def new_actions
          [:new, :create]
        end

        def member_action?
          !collection_actions.include? action
        end

        def new_object_url(options = {})
          if parent_data.present?
            cdx.new_polymorphic_url([:admin, parent, model_class], options)
          else
            cdx.new_polymorphic_url [:admin, model_class], options
          end
        end

        def edit_object_url(object, options = {})
          if parent_data.present?
            cdx.send "edit_admin_#{resource.model_name}_#{resource.object_name}_url", parent, object, options
          else
            cdx.send "edit_admin_#{resource.object_name}_url", object, options
          end
        end

        def edit_parent_object_url(options = {})
          cdx.send("edit_admin_#{parent.model_name.param_key}_url", parent, options) if parent_data.present?
        end

        def object_url(object = nil, options = {})
          target = object ? object : @object
          if parent_data.present?
            cdx.send "admin_#{resource.model_name}_#{resource.object_name}_url", parent, target, options
          else
            cdx.send "admin_#{resource.object_name}_url", target, options
          end
        end

        def parent_object_url(options = {})
          cdx.send("admin_#{parent.model_name.param_key}_url", parent, options) if parent_data.present?
        end

        def collection_url(options = {})
          if parent_data.present?
            cdx.polymorphic_url([:admin, parent, model_class], options)
          else
            cdx.polymorphic_url [:admin, model_class], options
          end
        end

        def parent_collection_url(options = {})
          cdx.polymorphic_url([:admin, parent], options) if parent_data.present?
        end

        def location_after_destroy
          collection_url
        end

        def location_after_save
          collection_url
        end

        def authorize_admin
          authorize! action, model_class
        end
    end
  end
end