Module: PunditExtraExtra::ResourceAutoload
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/pundit_extraextra/resource_autoload.rb
Defined Under Namespace
Modules: ClassMethods
Instance Method Summary collapse
- #authorize_resource(resource_name = nil, options = {}) ⇒ Object
- #create_new_resource(resource_name, action) ⇒ Object
- #find_parent_instance(parents) ⇒ Object
- #find_resource_by_id(current_instance, resource_name, resource_id, find_by_attribute) ⇒ Object
- #has_permitted_attributes?(resource, action) ⇒ Boolean
- #load_direct_resource(scope, action, resource_id, options = {}) ⇒ Object
- #load_index_resource(current_instance, resource_name) ⇒ Object
- #load_nested_resource(parent_instances, resource_name, current_instance) ⇒ Object
- #load_parent_resources(parents) ⇒ Object
- #load_resource(resource_name = nil, options = {}) ⇒ Object
- #load_singleton_resource(current_instance, resource_name, action, options) ⇒ Object
- #load_through_resource(parents, resource_name, resource_id, action, options) ⇒ Object
- #process_resource_callbacks ⇒ Object
- #resource_attributes(resource, action) ⇒ Object
- #resource_class ⇒ Object
- #resource_instance ⇒ Object
- #resource_name ⇒ Object
- #skip_action?(options) ⇒ Boolean
- #skip_authorization_and_scope ⇒ Object
- #update_resource(current_instance, resource_name, resource_id, find_by_attribute, action) ⇒ Object
Instance Method Details
#authorize_resource(resource_name = nil, options = {}) ⇒ Object
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 264 def (resource_name = nil, = {}) resource_name = (resource_name || controller_name.singularize).to_s instance_name = ([:instance_name] || resource_name).to_s resource = instance_variable_get("@#{instance_name}") || resource_name.classify.constantize # Determine if this is a parent resource by checking if it was listed as a `through` resource is_parent_resource = self.class..any? do |opt| opt[:options][:through] && Array(opt[:options][:through]).include?(resource_name.to_sym) end action = is_parent_resource ? :show : params[:action].to_sym if resource_name != controller_name.singularize action = :show end if resource.is_a?(Class) resource, "#{params[:action].to_sym}?" else resource, "#{action}?" end end |
#create_new_resource(resource_name, action) ⇒ Object
154 155 156 157 158 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 154 def create_new_resource(resource_name, action) new_resource = resource_name.classify.constantize.new new_resource.attributes = resource_attributes(new_resource, action) new_resource end |
#find_parent_instance(parents) ⇒ Object
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 124 def find_parent_instance(parents) Array(parents).each do |parent| parent_resource_name = parent.to_s.singularize parent_instance = instance_variable_get("@#{parent_resource_name}") return parent_instance if parent_instance end nil end |
#find_resource_by_id(current_instance, resource_name, resource_id, find_by_attribute) ⇒ Object
150 151 152 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 150 def find_resource_by_id(current_instance, resource_name, resource_id, find_by_attribute) current_instance.public_send(resource_name.pluralize).find_by(find_by_attribute => resource_id) end |
#has_permitted_attributes?(resource, action) ⇒ Boolean
338 339 340 341 342 343 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 338 def has_permitted_attributes?(resource, action) return true if policy(resource).respond_to? :"permitted_attributes_for_#{action}" return true if policy(resource).respond_to? :permitted_attributes false end |
#load_direct_resource(scope, action, resource_id, options = {}) ⇒ Object
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 214 def load_direct_resource(scope, action, resource_id, = {}) # Determine the attribute to find by and the parameter to use for the ID # if it isn't specified we assume we're finding by the 'id' column find_by_attribute = [:find_by] || :id if action == 'create' if resource_id resource = scope.find_by(find_by_attribute => resource_id) # Use the custom find_by attribute else new_resource = scope.new new_resource.attributes = resource_attributes(new_resource, action) if new_resource.respond_to?(:attributes=) resource = new_resource end elsif action == 'update' resource = scope.find_by(find_by_attribute => resource_id) # Use the custom find_by attribute unless resource.nil? resource, "#{action}?" resource.attributes = resource_attributes(resource, action) resource = resource else resource = nil end elsif action == 'index' resource = policy_scope(scope) # Treat as collection for index elsif resource_id resource = scope.find_by(find_by_attribute => resource_id) # Use the custom find_by attribute else resource = policy_scope(scope) # Treat as collection for non-standard actions end resource end |
#load_index_resource(current_instance, resource_name) ⇒ Object
145 146 147 148 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 145 def load_index_resource(current_instance, resource_name) resource = current_instance.public_send(resource_name.pluralize) policy_scope(resource) end |
#load_nested_resource(parent_instances, resource_name, current_instance) ⇒ Object
172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 172 def load_nested_resource(parent_instances, resource_name, current_instance) if parent_instances.size > 1 query = parent_instances.inject({}) do |hash, parent_instance| association_name = parent_instance.class.name.underscore.to_sym hash.merge!(association_name => parent_instance) end resource_name.classify.constantize.find_by(query) else current_instance.public_send(resource_name.pluralize) policy_scope(resource_name.classify.constantize) end end |
#load_parent_resources(parents) ⇒ Object
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 247 def load_parent_resources(parents) Array(parents).each do |parent| parent_resource_name = parent.to_s.singularize parent_id = params["#{parent_resource_name}_id"] parent_instance = instance_variable_get("@#{parent_resource_name}") unless parent_instance parent_scope = parent_resource_name.classify.constantize parent_instance = parent_scope.find(parent_id) instance_variable_set("@#{parent_resource_name}", parent_instance) parent_instance, :show? end parent_instance end end |
#load_resource(resource_name = nil, options = {}) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 68 def load_resource(resource_name = nil, = {}) resource_name = (resource_name || controller_name.singularize).to_s instance_name = [:instance_name] || resource_name scope = resource_name.classify.constantize action = params[:action] varname = instance_name # Use id_param option if provided, otherwise fallback to default pattern resource_id_param = [:id_param] || "#{resource_name}_id" resource_id = params[resource_id_param] || params[:id] if resource_name != controller_name.singularize # If the resource being loaded isn't the primary resource for the controller # we assume we are loading a single instance of it if [:through] # If there's a through option, find the parent instance current_instance = find_parent_instance([:through]) if current_instance if [:singleton] # If the relationship is has_one, we load the single associated instance resource = current_instance.public_send(resource_name) else # Otherwise, we find by resource_id or simply the first matching resource resource = resource_id ? current_instance.public_send(resource_name.pluralize).find(resource_id) : current_instance.public_send(resource_name.pluralize).first end else resource = nil end else # Load the resource directly if no `through` option or if `resource_id_param` is provided resource = scope.find(resource_id) end raise ActiveRecord::RecordNotFound, "No valid parent instance found through #{options[:through].join(', ')}" if resource == nil # Authorize the loaded resource for the 'show' action resource, "show?" else resource = if [:through] load_through_resource([:through], resource_name, resource_id, action, ) else load_direct_resource(scope, action, resource_id, ) end end raise ActiveRecord::RecordNotFound, "Couldn't find #{resource_name.to_s.capitalize} with #{resource_id_param} == #{resource_id}"if resource.nil? if resource.is_a?(ActiveRecord::Relation) || resource.is_a?(Array) varname = varname.to_s.pluralize end instance_variable_set("@#{varname}", resource) end |
#load_singleton_resource(current_instance, resource_name, action, options) ⇒ Object
135 136 137 138 139 140 141 142 143 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 135 def load_singleton_resource(current_instance, resource_name, action, ) if action == 'create' new_resource = resource_name.classify.constantize.new new_resource.attributes = resource_attributes(new_resource, action) if new_resource.respond_to?(:attributes=) new_resource else current_instance.public_send(resource_name) end end |
#load_through_resource(parents, resource_name, resource_id, action, options) ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 185 def load_through_resource(parents, resource_name, resource_id, action, ) parent_instances = Array(parents).map do |parent| instance_variable_get("@#{parent.to_s.singularize}") end.compact if parent_instances.empty? raise ActiveRecord::RecordNotFound, "No parent instance found for #{resource_name}" end current_instance = parent_instances.first find_by_attribute = [:find_by] || :id resource = if [:singleton] load_singleton_resource(current_instance, resource_name, action, ) elsif action == 'index' && (!resource_id && ![:singleton]) load_index_resource(current_instance, resource_name) elsif resource_id find_resource_by_id(current_instance, resource_name, resource_id, find_by_attribute) elsif action == 'create' create_new_resource(resource_name, action) elsif action == 'update' update_resource(current_instance, resource_name, resource_id, find_by_attribute, action) else load_index_resource(current_instance, resource_name) end resource end |
#process_resource_callbacks ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 47 def process_resource_callbacks self.class..each do |resource_option| next if skip_action?(resource_option[:options]) if resource_option[:action] == :load load_resource(resource_option[:resource_name], resource_option[:options]) elsif resource_option[:action] == :authorize (resource_option[:resource_name], resource_option[:options]) elsif resource_option[:action] == :load_and_authorize load_resource(resource_option[:resource_name], resource_option[:options]) (resource_option[:resource_name], resource_option[:options]) end end end |
#resource_attributes(resource, action) ⇒ Object
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 304 def resource_attributes(resource, action) attributes = {} # Get permitted attributes if they are defined if has_permitted_attributes?(resource, action) attributes = permitted_attributes(resource) else candidates = ["#{action}_params", "#{resource_name}_params"] candidates.each do |candidate| if respond_to?(candidate, true) attributes.merge!(send(candidate)) { |key, old_val, new_val| old_val } break end end end # Extract URL parameters that are part of the resource's attributes url_param_keys = request.path_parameters.keys.map(&:to_sym) # Remove :id from the keys to ensure it isn't included url_param_keys.delete(:id) relevant_url_params = params.slice(*url_param_keys).permit!.to_h # Merge only the relevant URL parameters that match resource's column names relevant_url_params.each do |key, value| if resource.class.column_names.include?(key.to_s) attributes[key.to_sym] ||= value end end attributes end |
#resource_class ⇒ Object
296 297 298 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 296 def resource_class resource_name.classify.constantize end |
#resource_instance ⇒ Object
300 301 302 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 300 def resource_instance instance_variable_get "@#{resource_name}" end |
#resource_name ⇒ Object
292 293 294 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 292 def resource_name controller_name.singularize end |
#skip_action?(options) ⇒ Boolean
62 63 64 65 66 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 62 def skip_action?() action = params[:action].to_sym ([:except] && Array([:except]).include?(action)) || ([:only] && !Array([:only]).include?(action)) end |
#skip_authorization_and_scope ⇒ Object
286 287 288 289 290 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 286 def action = params[:action] skip_policy_scope if action == 'index' end |
#update_resource(current_instance, resource_name, resource_id, find_by_attribute, action) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/pundit_extraextra/resource_autoload.rb', line 160 def update_resource(current_instance, resource_name, resource_id, find_by_attribute, action) resource = current_instance.public_send(resource_name.pluralize).find_by(find_by_attribute => resource_id) unless record.nil? resource, "#{action}?" resource.attributes = resource_attributes(resource, action) if resource.respond_to?(:attributes=) else resource = nil end resource end |