# frozen_string_literal: true module Admin class ResourceController < Spree::Admin::BaseController helper_method :new_object_url, :edit_object_url, :object_url, :collection_url before_action :load_resource, except: [:update_positions] rescue_from ActiveRecord::RecordNotFound, with: :resource_not_found rescue_from CanCan::AccessDenied, with: :unauthorized respond_to :html respond_to :js, except: [:show, :index] def new respond_with(@object) do |format| format.html { render layout: !request.xhr? } format.js { render layout: false } end end def edit respond_with(@object) do |format| format.html { render layout: !request.xhr? } format.js { render layout: false } end end def create @object.attributes = permitted_resource_params if @object.save flash[:success] = flash_message_for(@object, :successfully_created) respond_with(@object) do |format| format.html { redirect_to location_after_save } format.js { render layout: false } end else respond_with(@object) end end def update if @object.update(permitted_resource_params) flash[:success] = flash_message_for(@object, :successfully_updated) respond_with(@object) do |format| format.html { redirect_to location_after_save } format.js { render layout: false } end else respond_with(@object) end end def update_positions params[:positions].each do |id, index| model_class.where(id:).update_all(position: index) end respond_to do |format| format.js { render plain: 'Ok' } end end def destroy if @object.destroy flash[:success] = flash_message_for(@object, :successfully_removed) respond_with(@object) do |format| format.html { redirect_to collection_url } format.js { render partial: "spree/admin/shared/destroy" } end else respond_with(@object) do |format| format.html { redirect_to collection_url } end end end protected def resource_not_found flash[:error] = flash_message_for(model_class.new, :not_found) redirect_to collection_url end 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 def model_class controller_class_name.constantize end def model_name parent_data[:model_name].gsub('spree/', '') end def object_name controller_name.singularize end def load_resource if member_action? @object ||= load_resource_instance # call authorize! a third time (called twice already in Admin::BaseController) # this time we pass the actual instance so fine-grained abilities can control # access to individual records, not just entire models. authorize! action, @object instance_variable_set("@#{object_name}", @object) # If we don't have access, clear the object unless can? action, @object instance_variable_set("@#{object_name}", nil) end authorize! action, @object else @collection ||= collection # note: we don't call authorize here as the collection method should use # CanCan's accessible_by method to restrict the actual records returned instance_variable_set("@#{controller_name}", @collection) end end def load_resource_instance if new_actions.include?(action) build_resource elsif params[:id] find_resource end end def parent_data self.class.parent_data end def parent return nil if parent_data.blank? @parent ||= parent_data[:model_class]. find_by(parent_data[:find_by] => params["#{model_name}_id"]) instance_variable_set("@#{model_name}", @parent) end def find_resource if parent_data.present? parent.public_send(controller_name).find(params[:id]) else model_class.find(params[:id]) end end def build_resource if parent_data.present? parent.public_send(controller_name).build else model_class.new end end def collection return parent.public_send(controller_name) if parent_data.present? if model_class.respond_to?(:accessible_by) && !current_ability.has_block?(params[:action], model_class) model_class.accessible_by(current_ability, action) else model_class.scoped end end def location_after_save collection_url end # URL helpers def new_object_url(options = {}) if parent_data.present? url_helper.new_polymorphic_url([:admin, parent, model_class], options) else url_helper.new_polymorphic_url([:admin, model_class], options) end end def edit_object_url(object, options = {}) if parent_data.present? url_helper.public_send "edit_admin_#{model_name}_#{object_name}_url", parent, object, options else url_helper.public_send "edit_admin_#{object_name}_url", object, options end end def object_url(object = nil, options = {}) target = object || @object if parent_data.present? url_helper.public_send "admin_#{model_name}_#{object_name}_url", parent, target, options else url_helper.public_send "admin_#{object_name}_url", target, options end end # Permit specific list of params # # Example: params.require(object_name).permit(:name) def permitted_resource_params raise "All extending controllers need to override the method permitted_resource_params" end def collection_url(options = {}) if parent_data.present? url_helper.polymorphic_url([:admin, parent, model_class], options) else url_helper.polymorphic_url([:admin, model_class], options) end end def collection_actions [:index] end def member_action? collection_actions.exclude? action end def new_actions [:new, :create] end private def controller_class_name if spree_controller? "Spree::#{controller_name.classify}" else controller_name.classify.to_s end end def url_helper if spree_controller? spree else main_app end end def spree_controller? controller_path.starts_with? "spree" end end end