module RisosuSan def self.included(klass) #:nodoc: klass.extend ClassMethods end module ClassMethods # Adds a before filter which will take care of finding the parent resource. # # class PasswordsController < ActionController::Base # find_parent_resource :only => :new, :field => 'slug' # end # # :field setting is optional, if used and record is not found, there is a fallback to ID def find_parent_resource(options = {}) if options[:field] then field = options[:field] options.delete(:field) end before_filter options do |c| c.send(:find_parent_resource, field) end end end protected # Returns whether or not the request for the current resource is nested under # a parent resource, by reflecting on the params. # # params # => { :id => 42 } # nested? # => false # # params # => { :member_id => 24, :id => 42 } # nested? # => true def nested? !parent_resource_params.empty? end # Returns a hash of params for the parent resource, if available. # # params # => { :member_id => 24, :id => 42 } # parent_resource_params # => { :param => :member_id, :id => 24, :name => 'member', :class_name => 'Member', :class => Member } def parent_resource_params @parent_resource_params ||= if key = params.keys.find { |k| k =~ /^(\w+)_id$/ } { :param => key, :id => params[key], :name => $1, :class_name => $1.classify, :class => $1.classify.constantize } else {} end end # Finds the parent resource, if available, and assigns it to # @parent_resource and an instance variable with the name of the # resource. # # params # => { :member_id => 24, :id => 42 } # find_parent_resource # @parent_resource # => # # @member # => # # # OR: # # params # => { :member_id => 24, :id => 'this-is-a-unique-slug } # find_parent_resource, :field => 'slug' # @parent_resource # => # # @member # => # def find_parent_resource(field=nil) finder_sender = field ? "find_by_#{field}" : 'find' if @parent_resource.nil? && nested? && @parent_resource = parent_resource_params[:class].send(finder_sender, parent_resource_params[:id]) || parent_resource_params[:class].send('find', parent_resource_params[:id]) instance_variable_set("@#{parent_resource_params[:name]}", @parent_resource) end @parent_resource end end