inherited-resources-1.9.0/0000755000175000017500000000000013470613050016241 5ustar utkarsh2102utkarsh2102inherited-resources-1.9.0/lib/0000755000175000017500000000000013470613050017007 5ustar utkarsh2102utkarsh2102inherited-resources-1.9.0/lib/generators/0000755000175000017500000000000013470613050021160 5ustar utkarsh2102utkarsh2102inherited-resources-1.9.0/lib/generators/rails/0000755000175000017500000000000013470613050022272 5ustar utkarsh2102utkarsh2102inherited-resources-1.9.0/lib/generators/rails/USAGE0000644000175000017500000000074013470613050023062 0ustar utkarsh2102utkarsh2102Description: Stubs out a scaffolded controller and its views using InheritedResources. Pass the model name, either CamelCased or under_scored. The controller name is retrieved as a pluralized version of the model name. To create a controller within a module, specify the model name as a path like 'parent_module/controller_name'. This generates a controller class in app/controllers and invokes helper, template engine and test framework generators. inherited-resources-1.9.0/lib/generators/rails/inherited_resources_controller_generator.rb0000644000175000017500000000051013470613050033171 0ustar utkarsh2102utkarsh2102require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator' module Rails module Generators class InheritedResourcesControllerGenerator < ScaffoldControllerGenerator def self.source_root @source_root ||= File.expand_path("templates", File.dirname(__FILE__)) end end end endinherited-resources-1.9.0/lib/generators/rails/templates/0000755000175000017500000000000013470613050024270 5ustar utkarsh2102utkarsh2102inherited-resources-1.9.0/lib/generators/rails/templates/controller.rb0000644000175000017500000000065013470613050027001 0ustar utkarsh2102utkarsh2102class <%= controller_class_name %>Controller < InheritedResources::Base <% if options[:singleton] -%> defaults :singleton => true <% end -%> <% if Rails::VERSION::MAJOR >= 4 || defined?(ActiveModel::ForbiddenAttributesProtection) -%> private def <%= singular_name %>_params params.require(:<%= singular_name %>).permit(<%= attributes_names.map{ |a_name| ":#{a_name}" }.join(", ") %>) end <% end -%> end inherited-resources-1.9.0/lib/inherited_resources.rb0000644000175000017500000000324613470613050023406 0ustar utkarsh2102utkarsh2102# This is here because responders don't require it. require 'rails/engine' require 'responders' require 'inherited_resources/engine' require 'inherited_resources/blank_slate' require 'inherited_resources/responder' module InheritedResources ACTIONS = [ :index, :show, :new, :edit, :create, :update, :destroy ] unless self.const_defined?(:ACTIONS) autoload :Actions, 'inherited_resources/actions' autoload :BaseHelpers, 'inherited_resources/base_helpers' autoload :ShallowHelpers, 'inherited_resources/shallow_helpers' autoload :BelongsToHelpers, 'inherited_resources/belongs_to_helpers' autoload :ClassMethods, 'inherited_resources/class_methods' autoload :DSL, 'inherited_resources/dsl' autoload :PolymorphicHelpers, 'inherited_resources/polymorphic_helpers' autoload :SingletonHelpers, 'inherited_resources/singleton_helpers' autoload :UrlHelpers, 'inherited_resources/url_helpers' autoload :VERSION, 'inherited_resources/version' # Change the flash keys used by FlashResponder. def self.flash_keys=(array) Responders::FlashResponder.flash_keys = array end end ActiveSupport.on_load(:action_controller) do # We can remove this check and change to `on_load(:action_controller_base)` in Rails 5.2. if self == ActionController::Base # If you cannot inherit from InheritedResources::Base you can call # inherit_resources in your controller to have all the required modules and # funcionality included. def self.inherit_resources InheritedResources::Base.inherit_resources(self) initialize_resources_class_accessors! create_resources_url_helpers! end end end inherited-resources-1.9.0/lib/inherited_resources/0000755000175000017500000000000013470613050023054 5ustar utkarsh2102utkarsh2102inherited-resources-1.9.0/lib/inherited_resources/engine.rb0000644000175000017500000000052713470613050024652 0ustar utkarsh2102utkarsh2102module InheritedResources class Railtie < ::Rails::Engine config.inherited_resources = InheritedResources if config.respond_to?(:app_generators) config.app_generators.scaffold_controller = :inherited_resources_controller else config.generators.scaffold_controller = :inherited_resources_controller end end end inherited-resources-1.9.0/lib/inherited_resources/dsl.rb0000644000175000017500000000126513470613050024167 0ustar utkarsh2102utkarsh2102module InheritedResources # Allows controllers to write actions using a class method DSL. # # class MyController < InheritedResources::Base # create! do |success, failure| # success.html { render :text => "It works!" } # end # end # module DSL def self.included(base) ACTIONS.each do |action| base.class_eval <<-WRITTER def self.#{action}!(options={}, &block) define_method :__#{action}, &block class_eval <<-ACTION def #{action} super(\#{options.inspect}, &method(:__#{action})) end ACTION end WRITTER end end end end inherited-resources-1.9.0/lib/inherited_resources/class_methods.rb0000644000175000017500000004033413470613050026235 0ustar utkarsh2102utkarsh2102module InheritedResources module ClassMethods protected # Used to overwrite the default assumptions InheritedResources do. Whenever # this method is called, it should be on the top of your controller, since # almost other methods depends on the values given to <>defaults. # # == Options # # * :resource_class - The resource class which by default is guessed # by the controller name. Defaults to Project in # ProjectsController. # # * :collection_name - The name of the collection instance variable which # is set on the index action. Defaults to :projects in # ProjectsController. # # * :instance_name - The name of the singular instance variable which # is set on all actions besides index action. Defaults to # :project in ProjectsController. # # * :route_collection_name - The name of the collection route. Defaults to :collection_name. # # * :route_instance_name - The name of the singular route. Defaults to :instance_name. # # * :route_prefix - The route prefix which is automically set in namespaced # controllers. Default to :admin on Admin::ProjectsController. # # * :singleton - Tells if this controller is singleton or not. # # * :finder - Specifies which method should be called to instantiate the resource. # # defaults :finder => :find_by_slug # def defaults(options) raise ArgumentError, 'Class method :defaults expects a hash of options.' unless options.is_a? Hash options.symbolize_keys! options.assert_valid_keys(:resource_class, :collection_name, :instance_name, :class_name, :route_prefix, :route_collection_name, :route_instance_name, :singleton, :finder) self.resource_class = options[:resource_class] if options.key?(:resource_class) self.resource_class = options[:class_name].constantize if options.key?(:class_name) acts_as_singleton! if options.delete(:singleton) config = self.resources_configuration[:self] config[:route_prefix] = options.delete(:route_prefix) if options.key?(:route_prefix) if options.key?(:resource_class) or options.key?(:class_name) config[:request_name] = begin request_name = self.resource_class request_name = request_name.model_name.param_key if request_name.respond_to?(:model_name) request_name.to_s.underscore.gsub('/', '_') end options.delete(:resource_class) and options.delete(:class_name) end options.each do |key, value| config[key] = value.to_sym end create_resources_url_helpers! end # Defines wich actions will be inherited from the inherited controller. # Syntax is borrowed from resource_controller. # # actions :index, :show, :edit # actions :all, :except => :index # def actions(*actions_to_keep) raise ArgumentError, 'Wrong number of arguments. You have to provide which actions you want to keep.' if actions_to_keep.empty? options = actions_to_keep.extract_options! actions_to_remove = Array(options[:except]) actions_to_remove += ACTIONS - actions_to_keep.map { |a| a.to_sym } unless actions_to_keep.first == :all actions_to_remove.map! { |a| a.to_sym }.uniq! (instance_methods.map { |m| m.to_sym } & actions_to_remove).each do |action| undef_method action, "#{action}!" end end # Defines that this controller belongs to another resource. # # belongs_to :projects # # == Options # # * :parent_class - Allows you to specify what is the parent class. # # belongs_to :project, :parent_class => AdminProject # # * :class_name - Also allows you to specify the parent class, but you should # give a string. Added for ActiveRecord belongs to compatibility. # # * :instance_name - The instance variable name. By default is the name of the association. # # belongs_to :project, :instance_name => :my_project # # * :finder - Specifies which method should be called to instantiate the parent. # # belongs_to :project, :finder => :find_by_title! # # This will make your projects be instantiated as: # # Project.find_by_title!(params[:project_id]) # # Instead of: # # Project.find(params[:project_id]) # # * :param - Allows you to specify params key to retrieve the id. # Default is :association_id, which in this case is :project_id. # # * :route_name - Allows you to specify what is the route name in your url # helper. By default is association name. # # * :collection_name - Tell how to retrieve the next collection. Let's # suppose you have Tasks which belongs to Projects # which belongs to companies. This will do somewhere # down the road: # # @company.projects # # But if you want to retrieve instead: # # @company.admin_projects # # You supply the collection name. # # * :polymorphic - Tell the association is polymorphic. # # * :singleton - Tell it's a singleton association. # # * :optional - Tell the association is optional (it's a special # type of polymorphic association) # def belongs_to(*symbols, &block) options = symbols.extract_options! options.symbolize_keys! options.assert_valid_keys(:class_name, :parent_class, :instance_name, :param, :finder, :route_name, :collection_name, :singleton, :polymorphic, :optional, :shallow) optional = options.delete(:optional) shallow = options.delete(:shallow) polymorphic = options.delete(:polymorphic) finder = options.delete(:finder) include BelongsToHelpers if self.parents_symbols.empty? acts_as_polymorphic! if polymorphic || optional acts_as_shallow! if shallow raise ArgumentError, 'You have to give me at least one association name.' if symbols.empty? raise ArgumentError, "You cannot define multiple associations with options: #{options.keys.inspect} to belongs to." unless symbols.size == 1 || options.empty? symbols.each do |symbol| symbol = symbol.to_sym if polymorphic || optional self.parents_symbols << :polymorphic unless self.parents_symbols.include?(:polymorphic) self.resources_configuration[:polymorphic][:symbols] << symbol self.resources_configuration[:polymorphic][:optional] ||= optional else self.parents_symbols << symbol end self.resources_configuration[:self][:shallow] = true if shallow config = self.resources_configuration[symbol] = {} class_name = '' config[:parent_class] = options.delete(:parent_class) || begin class_name = if options[:class_name] options.delete(:class_name) else namespace = self.name.deconstantize model_name = symbol.to_s.pluralize.classify klass = model_name while namespace != '' new_klass = "#{namespace}::#{model_name}" if new_klass.safe_constantize klass = new_klass break else namespace = namespace.deconstantize end end klass = model_name if klass.start_with?('::') klass end class_name.constantize rescue NameError => e raise unless e.message.include?(class_name) nil end config[:singleton] = options.delete(:singleton) || false config[:collection_name] = options.delete(:collection_name) || symbol.to_s.pluralize.to_sym config[:instance_name] = options.delete(:instance_name) || symbol config[:param] = options.delete(:param) || :"#{symbol}_id" config[:route_name] = options.delete(:route_name) || symbol config[:finder] = finder || :find end if block_given? class_eval(&block) else create_resources_url_helpers! end helper_method :parent, :parent? end alias :nested_belongs_to :belongs_to # A quick method to declare polymorphic belongs to. # def polymorphic_belongs_to(*symbols, &block) options = symbols.extract_options! options.merge!(:polymorphic => true) belongs_to(*symbols, options, &block) end # A quick method to declare singleton belongs to. # def singleton_belongs_to(*symbols, &block) options = symbols.extract_options! options.merge!(:singleton => true) belongs_to(*symbols, options, &block) end # A quick method to declare optional belongs to. # def optional_belongs_to(*symbols, &block) options = symbols.extract_options! options.merge!(:optional => true) belongs_to(*symbols, options, &block) end # Defines custom restful actions by resource or collection basis. # # custom_actions :resource => [:delete, :transit], :collection => :search # # == Options # # * :resource - Allows you to specify resource actions. # custom_actions :resource => :delete # This macro creates 'delete' method in controller and defines # delete_resource_{path,url} helpers. The body of generated 'delete' # method is same as 'show' method. So you can override it if need # # * :collection - Allows you to specify collection actions. # custom_actions :collection => :search # This macro creates 'search' method in controller and defines # search_resources_{path,url} helpers. The body of generated 'search' # method is same as 'index' method. So you can override it if need # def custom_actions(options) self.resources_configuration[:self][:custom_actions] = options options.each do | resource_or_collection, actions | [*actions].each do | action | create_custom_action(resource_or_collection, action) end end create_resources_url_helpers! [*options[:resource]].each do | action | helper_method "#{action}_resource_path", "#{action}_resource_url" end [*options[:collection]].each do | action | helper_method "#{action}_resources_path", "#{action}_resources_url" end end # Defines the role to use when creating or updating resource. # Makes sense when using rails 3.1 mass assignment conventions def with_role(role) self.resources_configuration[:self][:role] = role.try(:to_sym) end def without_protection(flag) self.resources_configuration[:self][:without_protection] = flag end private def acts_as_singleton! #:nodoc: unless self.resources_configuration[:self][:singleton] self.resources_configuration[:self][:singleton] = true include SingletonHelpers actions :all, :except => :index end end def acts_as_polymorphic! #:nodoc: unless self.parents_symbols.include?(:polymorphic) include PolymorphicHelpers helper_method :parent_type, :parent_class end end def acts_as_shallow! #:nodoc: include BelongsToHelpers include ShallowHelpers end # Initialize resources class accessors and set their default values. # def initialize_resources_class_accessors! #:nodoc: # First priority is the namespaced model, e.g. User::Group self.resource_class ||= begin namespaced_class = self.name.sub(/Controller$/, '').singularize namespaced_class.constantize rescue NameError nil end # Second priority is the top namespace model, e.g. EngineName::Article for EngineName::Admin::ArticlesController self.resource_class ||= begin namespaced_classes = self.name.sub(/Controller$/, '').split('::') namespaced_class = [namespaced_classes.first, namespaced_classes.last].join('::').singularize namespaced_class.constantize rescue NameError nil end # Third priority the camelcased c, i.e. UserGroup self.resource_class ||= begin camelcased_class = self.name.sub(/Controller$/, '').gsub('::', '').singularize camelcased_class.constantize rescue NameError nil end # Otherwise use the Group class, or fail self.resource_class ||= begin class_name = self.controller_name.classify class_name.constantize rescue NameError => e raise unless e.message.include?(class_name) nil end self.parents_symbols = self.parents_symbols.try(:dup) || [] # Initialize resources configuration hash self.resources_configuration = self.resources_configuration.try(:dup) || {} self.resources_configuration.each do |key, value| next unless value.is_a?(Hash) || value.is_a?(Array) self.resources_configuration[key] = value.dup end config = (self.resources_configuration[:self] ||= {}) config[:collection_name] = self.controller_name.to_sym config[:instance_name] = self.controller_name.singularize.to_sym config[:route_collection_name] = config[:collection_name] config[:route_instance_name] = config[:instance_name] # Deal with namespaced controllers namespaces = self.controller_path.split('/')[0..-2] # Remove namespace if its a mountable engine namespaces.delete_if do |namespace| begin "#{namespace}/engine".camelize.constantize.isolated? rescue StandardError, LoadError false end end config[:route_prefix] = namespaces.join('_') unless namespaces.empty? # Deal with default request parameters in namespaced controllers, e.g. # Forum::Thread#create will properly pick up the request parameter # which will be forum_thread, and not thread # Additionally make this work orthogonally with instance_name config[:request_name] = self.resource_class.to_s.underscore.gsub('/', '_') # Initialize polymorphic, singleton, scopes and belongs_to parameters polymorphic = self.resources_configuration[:polymorphic] || { :symbols => [], :optional => false } polymorphic[:symbols] = polymorphic[:symbols].dup self.resources_configuration[:polymorphic] = polymorphic end def create_custom_action(resource_or_collection, action) class_eval <<-CUSTOM_ACTION, __FILE__, __LINE__ def #{action}(options={}, &block) respond_with(*with_chain(#{resource_or_collection}), options, &block) end alias :#{action}! :#{action} protected :#{action}! CUSTOM_ACTION end # Hook called on inheritance. # def inherited(base) #:nodoc: super(base) base.send :initialize_resources_class_accessors! base.send :create_resources_url_helpers! end end end inherited-resources-1.9.0/lib/inherited_resources/polymorphic_helpers.rb0000644000175000017500000001231413470613050027471 0ustar utkarsh2102utkarsh2102module InheritedResources # = polymorphic associations # # In some cases you have a resource that belongs to two different resources # but not at the same time. For example, let's suppose you have File, Message # and Task as resources and they are all commentable. # # Polymorphic associations allows you to create just one controller that will # deal with each case. # # class Comment < InheritedResources::Base # belongs_to :file, :message, :task, :polymorphic => true # end # # Your routes should be something like: # # resources :files do # resources :comments #=> /files/13/comments # end # resources :tasks do # resources :comments #=> /tasks/17/comments # end # resources :messages do # resources :comments #=> /messages/11/comments # end # # When using polymorphic associations, you get some free helpers: # # parent? #=> true # parent_type #=> :task # parent_class #=> Task # parent #=> @task # # This polymorphic controllers thing is a great idea by James Golick and he # built it in resource_controller. Here is just a re-implementation. # # = optional polymorphic associations # # Let's take another break from ProjectsController. Let's suppose we are # building a store, which sell products. # # On the website, we can show all products, but also products scoped to # categories, brands, users. In this case case, the association is optional, and # we deal with it in the following way: # # class ProductsController < InheritedResources::Base # belongs_to :category, :brand, :user, :polymorphic => true, :optional => true # end # # This will handle all those urls properly: # # /products/1 # /categories/2/products/5 # /brands/10/products/3 # /user/13/products/11 # # = nested polymorphic associations # # You can have polymorphic associations with nested resources. Let's suppose # that our File, Task and Message resources in the previous example belongs to # a project. # # This way we can have: # # class CommentsController < InheritedResources::Base # belongs_to :project { # belongs_to :file, :message, :task, :polymorphic => true # } # end # # Or: # # class CommentsController < InheritedResources::Base # nested_belongs_to :project # nested_belongs_to :file, :message, :task, :polymorphic => true # end # # Choose the syntax that makes more sense to you. :) # # Finally your routes should be something like: # # resources :projects do # resources :files do # resources :comments #=> /projects/1/files/13/comments # end # resources :tasks do # resources :comments #=> /projects/1/tasks/17/comments # end # resources :messages do # resources :comments #=> /projects/1/messages/11/comments # end # end # # The helpers work in the same way as above. # module PolymorphicHelpers protected # Returns the parent type. A Comments class can have :task, :file, :note # as parent types. # def parent_type unless @parent_type symbols_for_association_chain end @parent_type end def parent_class parent.class if parent_type end # Returns the parent object. They are also available with the instance # variable name: @task, @file, @note... # def parent if parent_type p = instance_variable_get("@#{parent_type}") p || instance_variable_set("@#{parent_type}", association_chain[-1]) end end # If the polymorphic association is optional, we might not have a parent. # def parent? if resources_configuration[:polymorphic][:optional] parents_symbols.size > 1 || !parent_type.nil? else true end end private # Maps parents_symbols to build association chain. # # If the parents_symbols find :polymorphic, it goes through the # params keys to see which polymorphic parent matches the given params. # # When optional is given, it does not raise errors if the polymorphic # params are missing. # def symbols_for_association_chain #:nodoc: polymorphic_config = resources_configuration[:polymorphic] parents_symbols.map do |symbol| if symbol == :polymorphic params_keys = params.keys keys = polymorphic_config[:symbols].map do |poly| params_keys.include?(resources_configuration[poly][:param].to_s) ? poly : nil end.compact if keys.empty? raise ScriptError, "Could not find param for polymorphic association. The request " << "parameters are #{params.keys.inspect} and the polymorphic " << "associations are #{polymorphic_config[:symbols].inspect}." unless polymorphic_config[:optional] nil else @parent_type = keys[-1].to_sym @parent_types = keys.map(&:to_sym) end else symbol end end.flatten.compact end end end inherited-resources-1.9.0/lib/inherited_resources/actions.rb0000644000175000017500000000314413470613050025043 0ustar utkarsh2102utkarsh2102module InheritedResources # Holds all default actions for InheritedResouces. module Actions # GET /resources def index(options={}, &block) respond_with(*with_chain(collection), options, &block) end alias :index! :index # GET /resources/1 def show(options={}, &block) respond_with(*with_chain(resource), options, &block) end alias :show! :show # GET /resources/new def new(options={}, &block) respond_with(*with_chain(build_resource), options, &block) end alias :new! :new # GET /resources/1/edit def edit(options={}, &block) respond_with(*with_chain(resource), options, &block) end alias :edit! :edit # POST /resources def create(options={}, &block) object = build_resource if create_resource(object) options[:location] ||= smart_resource_url end respond_with_dual_blocks(object, options, &block) end alias :create! :create # PUT /resources/1 def update(options={}, &block) object = resource if update_resource(object, resource_params) options[:location] ||= smart_resource_url end respond_with_dual_blocks(object, options, &block) end alias :update! :update # DELETE /resources/1 def destroy(options={}, &block) object = resource options[:location] ||= smart_collection_url destroy_resource(object) respond_with_dual_blocks(object, options, &block) end alias :destroy! :destroy # Make aliases protected protected :index!, :show!, :new!, :create!, :edit!, :update!, :destroy! end end inherited-resources-1.9.0/lib/inherited_resources/belongs_to_helpers.rb0000644000175000017500000000655513470613050027271 0ustar utkarsh2102utkarsh2102module InheritedResources # = belongs_to # # Let's suppose that we have some tasks that belongs to projects. To specify # this assoication in your controllers, just do: # # class TasksController < InheritedResources::Base # belongs_to :project # end # # belongs_to accepts several options to be able to configure the association. # For example, if you want urls like /projects/:project_title/tasks, you # can customize how InheritedResources find your projects: # # class TasksController < InheritedResources::Base # belongs_to :project, :finder => :find_by_title!, :param => :project_title # end # # It also accepts :route_name, :parent_class and :instance_name as options. # Check the lib/inherited_resources/class_methods.rb for more. # # = nested_belongs_to # # Now, our Tasks get some Comments and you need to nest even deeper. Good # practices says that you should never nest more than two resources, but sometimes # you have to for security reasons. So this is an example of how you can do it: # # class CommentsController < InheritedResources::Base # nested_belongs_to :project, :task # end # # If you need to configure any of these belongs to, you can nested them using blocks: # # class CommentsController < InheritedResources::Base # belongs_to :project, :finder => :find_by_title!, :param => :project_title do # belongs_to :task # end # end # # Warning: calling several belongs_to is the same as nesting them: # # class CommentsController < InheritedResources::Base # belongs_to :project # belongs_to :task # end # # In other words, the code above is the same as calling nested_belongs_to. # module BelongsToHelpers protected # Parent is always true when belongs_to is called. # def parent? true end def parent @parent ||= association_chain[-1] end def parent_type parent.class.name.underscore.to_sym end private # Evaluate the parent given. This is used to nest parents in the # association chain. # def evaluate_parent(parent_symbol, parent_config, chain = nil) #:nodoc: get_parent_ivar(parent_config[:instance_name]) || set_parent_instance(parent_config, chain) end def get_parent_ivar(instance_name) #:nodoc: instance_variable_defined?(:"@#{instance_name}") && instance_variable_get("@#{instance_name}") end def set_parent_instance(parent_config, chain) #:nodoc: if parent_config[:singleton] parent = if chain chain.send(parent_config[:instance_name]) else nil end else parent = if chain chain.send(parent_config[:collection_name]) else parent_config[:parent_class] end parent = parent.send(parent_config[:finder], params[parent_config[:param]]) end instance_variable_set("@#{parent_config[:instance_name]}", parent) end # Maps parents_symbols to build association chain. In this case, it # simply return the parent_symbols, however on polymorphic belongs to, # it has some customization. # def symbols_for_association_chain #:nodoc: parents_symbols end end end inherited-resources-1.9.0/lib/inherited_resources/version.rb0000644000175000017500000000007113470613050025064 0ustar utkarsh2102utkarsh2102module InheritedResources VERSION = '1.9.0'.freeze end inherited-resources-1.9.0/lib/inherited_resources/responder.rb0000644000175000017500000000017313470613050025403 0ustar utkarsh2102utkarsh2102module InheritedResources class Responder < ActionController::Responder include Responders::FlashResponder end end inherited-resources-1.9.0/lib/inherited_resources/base_helpers.rb0000644000175000017500000003163713470613050026047 0ustar utkarsh2102utkarsh2102# Whenever base is required load the dumb responder since it's used inside actions. require 'inherited_resources/blank_slate' module InheritedResources # Base helpers for InheritedResource work. Some methods here can be overwritten # and you will need to do that to customize your controllers from time to time. # module BaseHelpers protected # This is how the collection is loaded. # # You might want to overwrite this method if you want to add pagination # for example. When you do that, don't forget to cache the result in an # instance_variable: # # def collection # @projects ||= end_of_association_chain.paginate(params[:page]).all # end # def collection get_collection_ivar || begin c = end_of_association_chain if defined?(ActiveRecord::DeprecatedFinders) # ActiveRecord::Base#scoped and ActiveRecord::Relation#all # are deprecated in Rails 4. If it's a relation just use # it, otherwise use .all to get a relation. set_collection_ivar(c.is_a?(ActiveRecord::Relation) ? c : c.all) else set_collection_ivar(c.respond_to?(:scoped) ? c.scoped : c.all) end end end # This is how the resource is loaded. # # You might want to overwrite this method when you are using permalink. # When you do that, don't forget to cache the result in an # instance_variable: # # def resource # @project ||= end_of_association_chain.find_by_permalink!(params[:id]) # end # # You also might want to add the exclamation mark at the end of the method # because it will raise a 404 if nothing can be found. Otherwise it will # probably render a 500 error message. # def resource get_resource_ivar || set_resource_ivar(end_of_association_chain.send(method_for_find, params[:id])) end # This method is responsible for building the object on :new and :create # methods. If you overwrite it, don't forget to cache the result in an # instance variable. # def build_resource get_resource_ivar || set_resource_ivar(end_of_association_chain.send(method_for_build, *resource_params)) end # Responsible for saving the resource on :create method. Overwriting this # allow you to control the way resource is saved. Let's say you have a # PassworsController who is responsible for finding an user by email and # sent password instructions for him. Instead of overwriting the entire # :create method, you could do something: # # def create_resource(object) # object.send_instructions_by_email # end # def create_resource(object) object.save end # Responsible for updating the resource in :update method. This allow you # to handle how the resource is going to be updated, let's say in a different # way than the usual :update_attributes: # # def update_resource(object, attributes) # object.reset_password!(attributes) # end # def update_resource(object, attributes) object.update_attributes(*attributes) end # Handle the :destroy method for the resource. Overwrite it to call your # own method for destroying the resource, as: # # def destroy_resource(object) # object.cancel # end # def destroy_resource(object) object.destroy end # This class allows you to set a instance variable to begin your # association chain. For example, usually your projects belongs to users # and that means that they belong to the current logged in user. So you # could do this: # # def begin_of_association_chain # @current_user # end # # So every time we instantiate a project, we will do: # # @current_user.projects.build(params[:project]) # @current_user.projects.find(params[:id]) # # The variable set in begin_of_association_chain is not sent when building # urls, so this is never going to happen when calling resource_url: # # project_url(@current_user, @project) # # If the user actually scopes the url, you should use belongs_to method # and declare that projects belong to user. # def begin_of_association_chain nil end # Returns if the controller has a parent. When only base helpers are loaded, # it's always false and should not be overwritten. # def parent? false end # Returns the association chain, with all parents (does not include the # current resource). # def association_chain @association_chain ||= symbols_for_association_chain.inject([begin_of_association_chain]) do |chain, symbol| chain << evaluate_parent(symbol, resources_configuration[symbol], chain.last) end.compact.freeze end # Overwrite this method to provide other interpolation options when # the flash message is going to be set. # # def flash_interpolation_options # { } # end private # Adds the given object to association chain. def with_chain(object) association_chain + [ object ] end # Fast accessor to resource_collection_name # def resource_collection_name #:nodoc: self.resources_configuration[:self][:collection_name] end # Fast accessor to resource_instance_name # def resource_instance_name #:nodoc: self.resources_configuration[:self][:instance_name] end def resource_request_name self.resources_configuration[:self][:request_name] end # This methods gets your begin_of_association_chain, join it with your # parents chain and returns the scoped association. def end_of_association_chain #:nodoc: if chain = association_chain.last if method_for_association_chain apply_scopes_if_available(chain.send(method_for_association_chain)) else # This only happens when we specify begin_of_association_chain in # a singleton controller without parents. In this case, the chain # is exactly the begin_of_association_chain which is already an # instance and then not scopable. chain end else apply_scopes_if_available(resource_class) end end # Returns the appropriated method to build the resource. # def method_for_build #:nodoc: (begin_of_association_chain || parent?) ? method_for_association_build : :new end # Returns the name of the method used for building the resource in cases # where we have a parent. This is overwritten in singleton scenarios. # def method_for_association_build :build end # Returns the name of the method to be called, before returning the end # of the association chain. This is overwritten by singleton cases # where no method for association chain is called. # def method_for_association_chain #:nodoc: resource_collection_name end # Returns finder method for instantiate resource by params[:id] def method_for_find resources_configuration[:self][:finder] || :find end # Get resource ivar based on the current resource controller. # def get_resource_ivar #:nodoc: if instance_variable_defined?(:"@#{resource_instance_name}") instance_variable_get("@#{resource_instance_name}") else nil end end # Set resource ivar based on the current resource controller. # def set_resource_ivar(resource) #:nodoc: instance_variable_set("@#{resource_instance_name}", resource) end # Get collection ivar based on the current resource controller. # def get_collection_ivar #:nodoc: if instance_variable_defined?(:"@#{resource_collection_name}") instance_variable_get("@#{resource_collection_name}") else nil end end # Set collection ivar based on the current resource controller. # def set_collection_ivar(collection) #:nodoc: instance_variable_set("@#{resource_collection_name}", collection) end # Used to allow to specify success and failure within just one block: # # def create # create! do |success, failure| # failure.html { redirect_to root_url } # end # end # # It also calculates the response url in case a block without arity is # given and returns it. Otherwise returns nil. # def respond_with_dual_blocks(object, options, &block) #:nodoc: args = (with_chain(object) << options) case block.try(:arity) when 2 respond_with(*args) do |responder| blank_slate = InheritedResources::BlankSlate.new if object.errors.empty? block.call(responder, blank_slate) else block.call(blank_slate, responder) end end when 1 respond_with(*args, &block) else options[:location] = block.call if block respond_with(*args) end end # Hook to apply scopes. By default returns only the target_object given. # It's extend by HasScopeHelpers. # def apply_scopes_if_available(target_object) #:nodoc: respond_to?(:apply_scopes, true) ? apply_scopes(target_object) : target_object end # Symbols chain in base helpers return nothing. This is later overwritten # by belongs_to and can be complex in polymorphic cases. # def symbols_for_association_chain #:nodoc: [] end # URL to redirect to when redirect implies resource url. def smart_resource_url url = nil if respond_to? :show url = resource_url rescue nil end url ||= smart_collection_url end # URL to redirect to when redirect implies collection url. def smart_collection_url url = nil if respond_to? :index url ||= collection_url rescue nil end if respond_to? :parent, true url ||= parent_url rescue nil end url ||= root_url rescue nil end # memoize the extraction of attributes from params def resource_params @resource_params ||= build_resource_params end def resource_params_method_name "#{resource_instance_name}_params" end # Returns hash of sanitized params in a form like # `{:project => {:project_attribute => 'value'}}` # # This method makes use of `project_params` (or `smth_else_params`) which # is a default Rails controller method for strong parameters definition. # # `permitted_params` is usually fired by method :new, :create, :update # actions. Action :new usually has no parameters so strong parameters # `require` directive raises a +ActionController::ParameterMissing+ # exception. `#permitted_params` rescues such exceptions in :new and # returns an empty hash of parameters (which is reasonable default). # If for any reasons you need something more specific, you can redefine # this method in a way previous `inherited_resources` versions did: # # # Unnecessary redefinition # def permitted_params # params.permit(:project => [:project_attribute]) # end # def permitted_params return nil unless respond_to?(resource_params_method_name, true) {resource_request_name => send(resource_params_method_name)} rescue ActionController::ParameterMissing # typically :new action if params[:action].to_s == 'new' {resource_request_name => {}} else raise end end # extract attributes from params def build_resource_params parameters = permitted_params || params rparams = [parameters[resource_request_name] || parameters[resource_instance_name] || {}] if without_protection_given? rparams << without_protection else rparams << as_role if role_given? end rparams end # checking if role given def role_given? self.resources_configuration[:self][:role].present? end # getting role for mass-asignment def as_role { :as => self.resources_configuration[:self][:role] } end def without_protection_given? self.resources_configuration[:self][:without_protection].present? end def without_protection { :without_protection => self.resources_configuration[:self][:without_protection] } end end end inherited-resources-1.9.0/lib/inherited_resources/shallow_helpers.rb0000644000175000017500000000306513470613050026600 0ustar utkarsh2102utkarsh2102module InheritedResources # Shallow provides a functionality that goes on pair with Rails' shallow. # It is very similar to "optional" but it actually finds all the parents # resources instead of leaving them blank. Consider the following example: # # belongs_to :post, :shallow => true do # belongs_to :comment # end # # When accessed as /comments/1, Inherited Resources will automatically get # the post resource so both objects are actually accessible through the views. # # However, when using optional, Inherited Resources wouldn't actually bother # with finding the parent object. module ShallowHelpers private def symbols_for_association_chain #:nodoc: parent_symbols = parents_symbols.dup instance = nil if id = params[:id] finder_method = resources_configuration[:self][:finder] || :find instance = self.resource_class.send(finder_method, id) elsif parents_symbols.size > 1 config = resources_configuration[parent_symbols.pop] finder_method = config[:finder] || :find instance = config[:parent_class].send(finder_method, params[config[:param]]) end load_parents(instance, parent_symbols) if instance parents_symbols end def load_parents(instance, parent_symbols) parent_symbols.reverse.each do |parent| instance = instance.send(parent) config = resources_configuration[parent] params[config[:param]] = instance.to_param end end end end inherited-resources-1.9.0/lib/inherited_resources/singleton_helpers.rb0000644000175000017500000000511413470613050027126 0ustar utkarsh2102utkarsh2102module InheritedResources # = singleton # # Singletons are usually used in associations which are related through has_one # and belongs_to. You declare those associations like this: # # class ManagersController < InheritedResources::Base # belongs_to :project, :singleton => true # end # # But in some cases, like an AccountsController, you have a singleton object # that is not necessarily associated with another: # # class AccountsController < InheritedResources::Base # defaults :singleton => true # end # # Besides that, you should overwrite the methods :resource and :build_resource # to make it work properly: # # class AccountsController < InheritedResources::Base # defaults :singleton => true # # protected # def resource # @current_user.account # end # # def build_resource(attributes = {}) # Account.new(attributes) # end # end # # When you have a singleton controller, the action index is removed. # module SingletonHelpers protected # Singleton methods does not deal with collections. # def collection nil end # Overwrites how singleton deals with resource. # # If you are going to overwrite it, you should notice that the # end_of_association_chain here is not the same as in default belongs_to. # # class TasksController < InheritedResources::Base # belongs_to :project # end # # In this case, the association chain would be: # # Project.find(params[:project_id]).tasks # # So you would just have to call find(:all) at the end of association # chain. And this is what happened. # # In singleton controllers: # # class ManagersController < InheritedResources::Base # belongs_to :project, :singleton => true # end # # The association chain will be: # # Project.find(params[:project_id]) # # So we have to call manager on it, not find. # def resource get_resource_ivar || set_resource_ivar(end_of_association_chain.send(resource_instance_name)) end private # Returns the appropriated method to build the resource. # def method_for_association_build #:nodoc: :"build_#{resource_instance_name}" end # Sets the method_for_association_chain to nil. See resource # above for more information. # def method_for_association_chain #:nodoc: nil end end end inherited-resources-1.9.0/lib/inherited_resources/blank_slate.rb0000644000175000017500000000041313470613050025656 0ustar utkarsh2102utkarsh2102module InheritedResources # An object from BlankSlate simply discards all messages sent to it. class BlankSlate instance_methods.each do |m| undef_method m unless m =~ /^(__|object_id)/ end def method_missing(*args) nil end end end inherited-resources-1.9.0/lib/inherited_resources/url_helpers.rb0000644000175000017500000002174613470613050025737 0ustar utkarsh2102utkarsh2102module InheritedResources # = URLHelpers # # When you use InheritedResources it creates some UrlHelpers for you. # And they handle everything for you. # # # /posts/1/comments # resource_url # => /posts/1/comments/#{@comment.to_param} # resource_url(comment) # => /posts/1/comments/#{comment.to_param} # new_resource_url # => /posts/1/comments/new # edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit # collection_url # => /posts/1/comments # parent_url # => /posts/1 # # # /projects/1/tasks # resource_url # => /projects/1/tasks/#{@task.to_param} # resource_url(task) # => /projects/1/tasks/#{task.to_param} # new_resource_url # => /projects/1/tasks/new # edit_resource_url # => /projects/1/tasks/#{@task.to_param}/edit # collection_url # => /projects/1/tasks # parent_url # => /projects/1 # # # /users # resource_url # => /users/#{@user.to_param} # resource_url(user) # => /users/#{user.to_param} # new_resource_url # => /users/new # edit_resource_url # => /users/#{@user.to_param}/edit # collection_url # => /users # parent_url # => / # # The nice thing is that those urls are not guessed during runtime. They are # all created when you inherit. # module UrlHelpers protected # This method hard code url helpers in the class. # # We are doing this because is cheaper than guessing them when our action # is being processed (and even more cheaper when we are using nested # resources). # # When we are using polymorphic associations, those helpers rely on # polymorphic_url Rails helper. # def create_resources_url_helpers! resource_segments, resource_ivars = [], [] resource_config = self.resources_configuration[:self] singleton = resource_config[:singleton] uncountable = !singleton && resource_config[:route_collection_name] == resource_config[:route_instance_name] polymorphic = self.parents_symbols.include?(:polymorphic) # Add route_prefix if any. unless resource_config[:route_prefix].blank? if polymorphic resource_ivars << resource_config[:route_prefix].to_s.inspect else resource_segments << resource_config[:route_prefix] end end # Deal with belongs_to associations and polymorphic associations. # Remember that we don't have to build the segments in polymorphic cases, # because the url will be polymorphic_url. # self.parents_symbols.each do |symbol| if symbol == :polymorphic resource_ivars << :parent else config = self.resources_configuration[symbol] if config[:singleton] && polymorphic resource_ivars << config[:instance_name].inspect else resource_segments << config[:route_name] end if !config[:singleton] resource_ivars << :"@#{config[:instance_name]}" end end end collection_ivars = resource_ivars.dup collection_segments = resource_segments.dup # Generate parent url before we add resource instances. unless parents_symbols.empty? generate_url_and_path_helpers nil, :parent, resource_segments, resource_ivars generate_url_and_path_helpers :edit, :parent, resource_segments, resource_ivars end # This is the default route configuration, later we have to deal with # exception from polymorphic and singleton cases. # collection_segments << resource_config[:route_collection_name] resource_segments << resource_config[:route_instance_name] resource_ivars << :"@#{resource_config[:instance_name]}" # In singleton cases, we do not send the current element instance variable # because the id is not in the URL. For example, we should call: # # project_manager_url(@project) # # Instead of: # # project_manager_url(@project, @manager) # # Another exception in singleton cases is that collection url does not # exist. In such cases, we create the parent collection url. So in the # manager case above, the collection url will be: # # project_url(@project) # # If the singleton does not have a parent, it will default to root_url. # # Finally, polymorphic cases we have to give hints to the polymorphic url # builder. This works by attaching new ivars as symbols or records. # if singleton collection_segments.pop resource_ivars.pop if polymorphic resource_ivars << resource_config[:instance_name].inspect new_ivars = resource_ivars end elsif polymorphic collection_ivars << '(@_resource_class_new ||= resource_class.new)' end # If route is uncountable then add "_index" suffix to collection index route name if uncountable collection_segments << :"#{collection_segments.pop}_index" end generate_url_and_path_helpers nil, :collection, collection_segments, collection_ivars generate_url_and_path_helpers :new, :resource, resource_segments, new_ivars || collection_ivars generate_url_and_path_helpers nil, :resource, resource_segments, resource_ivars generate_url_and_path_helpers :edit, :resource, resource_segments, resource_ivars if resource_config[:custom_actions] [*resource_config[:custom_actions][:resource]].each do | method | generate_url_and_path_helpers method, :resource, resource_segments, resource_ivars end [*resource_config[:custom_actions][:collection]].each do | method | generate_url_and_path_helpers method, :resources, collection_segments, collection_ivars end end end def handle_shallow_resource(prefix, name, segments, ivars) #:nodoc: return segments, ivars unless self.resources_configuration[:self][:shallow] case name when :collection, :resources segments = segments[-2..-1] ivars = [ivars.last] when :resource if prefix == :new segments = segments[-2..-1] ivars = [ivars.last] else segments = [segments.last] ivars = [ivars.last] end when :parent segments = [segments.last] ivars = [ivars.last] end segments ||= [] unless self.resources_configuration[:self][:route_prefix].blank? segments.unshift self.resources_configuration[:self][:route_prefix] end return segments, ivars end def generate_url_and_path_helpers(prefix, name, resource_segments, resource_ivars) #:nodoc: resource_segments, resource_ivars = handle_shallow_resource(prefix, name, resource_segments, resource_ivars) ivars = resource_ivars.dup singleton = self.resources_configuration[:self][:singleton] polymorphic = self.parents_symbols.include?(:polymorphic) # If it's not a singleton, ivars are not empty, not a collection or # not a "new" named route, we can pass a resource as argument. # unless (singleton && name != :parent) || ivars.empty? || name == :collection || prefix == :new ivars.push "(given_args.first || #{ivars.pop})" end # In collection in polymorphic cases, allow an argument to be given as a # replacemente for the parent. # if name == :collection && polymorphic index = ivars.index(:parent) ivars.insert index, "(given_args.first || parent)" ivars.delete(:parent) end # When polymorphic is true, the segments must be replace by :polymorphic # and ivars should be gathered into an array, which is compacted when # optional. # if polymorphic segments = :polymorphic ivars = "[#{ivars.join(', ')}]" ivars << '.compact' if self.resources_configuration[:polymorphic][:optional] else segments = resource_segments.empty? ? 'root' : resource_segments.join('_') ivars = ivars.join(', ') end prefix = prefix ? "#{prefix}_" : '' ivars << (ivars.empty? ? 'given_options' : ', given_options') given_args_transform = 'given_args = given_args.collect { |arg| arg.respond_to?(:permitted?) ? arg.to_h : arg }' class_eval <<-URL_HELPERS, __FILE__, __LINE__ protected undef :#{prefix}#{name}_path if method_defined? :#{prefix}#{name}_path def #{prefix}#{name}_path(*given_args) #{given_args_transform} given_options = given_args.extract_options! #{prefix}#{segments}_path(#{ivars}) end undef :#{prefix}#{name}_url if method_defined? :#{prefix}#{name}_url def #{prefix}#{name}_url(*given_args) #{given_args_transform} given_options = given_args.extract_options! #{prefix}#{segments}_url(#{ivars}) end URL_HELPERS end end end inherited-resources-1.9.0/MIT-LICENSE0000644000175000017500000000204413470613050017675 0ustar utkarsh2102utkarsh2102Copyright (c) 2009-2017 José Valim Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. inherited-resources-1.9.0/app/0000755000175000017500000000000013470613050017021 5ustar utkarsh2102utkarsh2102inherited-resources-1.9.0/app/controllers/0000755000175000017500000000000013470613050021367 5ustar utkarsh2102utkarsh2102inherited-resources-1.9.0/app/controllers/inherited_resources/0000755000175000017500000000000013470613050025434 5ustar utkarsh2102utkarsh2102inherited-resources-1.9.0/app/controllers/inherited_resources/base.rb0000644000175000017500000000350313470613050026674 0ustar utkarsh2102utkarsh2102module InheritedResources # = Base # # This is the base class that holds all actions. If you see the code for each # action, they are quite similar to Rails default scaffold. # # To change your base behavior, you can overwrite your actions and call super, # call default class method, call <actions class method # or overwrite some helpers in the base_helpers.rb file. # class Base < ::ApplicationController # Overwrite inherit_resources to add specific InheritedResources behavior. def self.inherit_resources(base) base.class_eval do include InheritedResources::Actions include InheritedResources::BaseHelpers extend InheritedResources::ClassMethods extend InheritedResources::UrlHelpers # Add at least :html mime type respond_to :html if self.mimes_for_respond_to.empty? self.responder = InheritedResources::Responder helper_method :resource, :collection, :resource_class, :association_chain, :resource_instance_name, :resource_collection_name, :resource_url, :resource_path, :collection_url, :collection_path, :new_resource_url, :new_resource_path, :edit_resource_url, :edit_resource_path, :parent_url, :parent_path, :smart_resource_url, :smart_collection_url self.class_attribute :resource_class, :instance_writer => false unless self.respond_to? :resource_class self.class_attribute :parents_symbols, :resources_configuration, :instance_writer => false protected :resource_class, :parents_symbols, :resources_configuration, :resource_class?, :parents_symbols?, :resources_configuration? end end inherit_resources(self) end endinherited-resources-1.9.0/README.md0000644000175000017500000005073513470613050017532 0ustar utkarsh2102utkarsh2102## Notice Inherited Resources is no longer actively maintained by the original author and has been transferred to the ActiveAdmin organization for maintenance. New feature requests are not encouraged. If you are not already using Inherited Resources we suggest instead using Rails' `respond_with` feature alongside the [responders gem](https://github.com/plataformatec/responders). ## Inherited Resources [![Version](http://img.shields.io/gem/v/inherited_resources.svg)](https://rubygems.org/gems/inherited_resources) [![Travis CI](http://img.shields.io/travis/activeadmin/inherited_resources/master.svg)](https://travis-ci.org/activeadmin/inherited_resources) Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important. It makes your controllers more powerful and cleaner at the same time. In addition to making your controllers follow a pattern, it helps you to write better code by following fat models and skinny controllers convention. There are two screencasts available besides this README: * http://railscasts.com/episodes/230-inherited-resources * http://akitaonrails.com/2009/09/01/screencast-real-thin-restful-controllers-with-inherited-resources ## Installation You can let bundler install Inherited Resources by adding this line to your application's Gemfile: ```ruby gem 'inherited_resources' ``` And then execute: ```sh $ bundle install ``` Or install it yourself with: ```sh $ gem install inherited_resources ``` ## HasScope Since Inherited Resources 1.0, has_scope is not part of its core anymore but a gem dependency. Be sure to check the documentation to see how you can use it: - And it can be installed as: ```sh $ gem install has_scope ``` ## Responders Since Inherited Resources 1.0, responders are not part of its core anymore, but is set as Inherited Resources dependency and it's used by default by InheritedResources controllers. Be sure to check the documentation to see how it will change your application: - And it can be installed with: ```sh $ gem install responders ``` Using responders will set the flash message to :notice and :alert. You can change that through the following configuration value: ```ruby InheritedResources.flash_keys = [ :success, :failure ] ``` Notice the CollectionResponder won't work with InheritedResources, as InheritedResources hardcodes the redirect path based on the current scope (like belongs to, polymorphic associations, etc). ## Basic Usage To use Inherited Resources you just have to inherit (duh) it: ```ruby class ProjectsController < InheritedResources::Base end ``` And all actions are defined and working, check it! Your projects collection (in the index action) is still available in the instance variable `@projects` and your project resource (all other actions) is available as `@project`. The next step is to define which mime types this controller provides: ```ruby class ProjectsController < InheritedResources::Base respond_to :html, :xml, :json end ``` You can also specify them per action: ```ruby class ProjectsController < InheritedResources::Base respond_to :html, :xml, :json respond_to :js, :only => :create respond_to :iphone, :except => [ :edit, :update ] end ``` For each request, it first checks if the "controller/action.format" file is available (for example "projects/create.xml") and if it's not, it checks if the resource respond to :to_format (in this case, `:to_xml`). Otherwise returns 404. Another option is to specify which actions the controller will inherit from the `InheritedResources::Base`: ```ruby class ProjectsController < InheritedResources::Base actions :index, :show, :new, :create end ``` Or: ```ruby class ProjectsController < InheritedResources::Base actions :all, :except => [ :edit, :update, :destroy ] end ``` In your views, you will get the following helpers: ```ruby resource #=> @project collection #=> @projects resource_class #=> Project ``` As you might expect, collection (`@projects` instance variable) is only available on index actions. If for some reason you cannot inherit from `InheritedResources::Base`, you can call inherit_resources in your controller class scope: ```ruby class AccountsController < ApplicationController inherit_resources end ``` One reason to use the `inherit_resources` macro would be to ensure that your controller never responds with the html mime-type. `InheritedResources::Base` already responds to `:html`, and the `respond_to` macro is strictly additive. Therefore, if you want to create a controller that, for example, responds ONLY via `:js`, you will have to write it this way: ```ruby class AccountsController < ApplicationController respond_to :js inherit_resources end ``` ## Overwriting defaults Whenever you inherit from InheritedResources, several defaults are assumed. For example you can have an `AccountsController` for account management while the resource is a `User`: ```ruby class AccountsController < InheritedResources::Base defaults :resource_class => User, :collection_name => 'users', :instance_name => 'user' end ``` In the case above, in your views you will have `@users` and `@user` variables, but the routes used will still be `accounts_url` and `account_url`. If you plan also to change the routes, you can use `:route_collection_name` and `:route_instance_name`. Namespaced controllers work out of the box, but if you need to specify a different route prefix you can do the following: ```ruby class Administrators::PeopleController < InheritedResources::Base defaults :route_prefix => 'admin' end ``` Then your named routes will be: `admin_people_url`, `admin_person_url` instead of `administrators_people_url` and `administrators_person_url`. If you want to customize how resources are retrieved you can overwrite collection and resource methods. The first is called on index action and the second on all other actions. Let's suppose you want to add pagination to your projects collection: ```ruby class ProjectsController < InheritedResources::Base protected def collection get_collection_ivar || set_collection_ivar(end_of_association_chain.paginate(:page => params[:page])) end end ``` The `end_of_association_chain` returns your resource after nesting all associations and scopes (more about this below). InheritedResources also introduces another method called `begin_of_association_chain`. It's mostly used when you want to create resources based on the `@current_user` and you have urls like "account/projects". In such cases you have to do `@current_user.projects.find` or `@current_user.projects.build` in your actions. You can deal with it just by doing: ```ruby class ProjectsController < InheritedResources::Base protected def begin_of_association_chain @current_user end end ``` ## Overwriting actions Let's suppose that after destroying a project you want to redirect to your root url instead of redirecting to projects url. You just have to do: ```ruby class ProjectsController < InheritedResources::Base def destroy super do |format| format.html { redirect_to root_url } end end end ``` You are opening your action and giving the parent action a new behavior. On the other hand, I have to agree that calling super is not very readable. That's why all methods have aliases. So this is equivalent: ```ruby class ProjectsController < InheritedResources::Base def destroy destroy! do |format| format.html { redirect_to root_url } end end end ``` Since most of the time when you change a create, update or destroy action you do so because you want to change its redirect url, a shortcut is provided. So you can do: ```ruby class ProjectsController < InheritedResources::Base def destroy destroy! { root_url } end end ``` If you simply want to change the flash message for a particular action, you can pass the message to the parent action using the keys `:notice` and `:alert` (as you would with flash): ```ruby class ProjectsController < InheritedResources::Base def create create!(:notice => "Dude! Nice job creating that project.") end end ``` You can still pass the block to change the redirect, as mentioned above: ```ruby class ProjectsController < InheritedResources::Base def create create!(:notice => "Dude! Nice job creating that project.") { root_url } end end ``` Now let's suppose that before create a project you have to do something special but you don't want to create a before filter for it: ```ruby class ProjectsController < InheritedResources::Base def create @project = Project.new(params[:project]) @project.something_special! create! end end ``` Yes, it's that simple! The nice part is since you already set the instance variable `@project`, it will not build a project again. Same goes for updating the project: ```ruby class ProjectsController < InheritedResources::Base def update @project = Project.find(params[:id]) @project.something_special! update! end end ``` Before we finish this topic, we should talk about one more thing: "success/failure blocks". Let's suppose that when we update our project, in case of failure, we want to redirect to the project url instead of re-rendering the edit template. Our first attempt to do this would be: ```ruby class ProjectsController < InheritedResources::Base def update update! do |format| unless @project.errors.empty? # failure format.html { redirect_to project_url(@project) } end end end end ``` Looks too verbose, right? We can actually do: ```ruby class ProjectsController < InheritedResources::Base def update update! do |success, failure| failure.html { redirect_to project_url(@project) } end end end ``` Much better! So explaining everything: when you give a block which expects one argument it will be executed in both scenarios: success and failure. But if you give a block that expects two arguments, the first will be executed only in success scenarios and the second in failure scenarios. You keep everything clean and organized inside the same action. ## Smart redirects Although the syntax above is a nice shortcut, you won't need to do it frequently because (since version 1.2) Inherited Resources has smart redirects. Redirects in actions calculates depending on the existent controller methods. Redirects in create and update actions calculates in the following order: `resource_url`, `collection_url`, `parent_url` (which we are going to see later), and `root_url`. Redirect in destroy action calculate in following order `collection_url`, `parent_url`, `root_url`. Example: ```ruby class ButtonsController < InheritedResources::Base belongs_to :window actions :all, :except => [:show, :index] end ``` This controller redirect to parent window after all CUD actions. ## Success and failure scenarios on destroy The destroy action can also fail, this usually happens when you have a `before_destroy` callback in your model which returns false. However, in order to tell InheritedResources that it really failed, you need to add errors to your model. So your `before_destroy` callback on the model should be something like this: ```ruby def before_destroy if cant_be_destroyed? errors.add(:base, "not allowed") false end end ``` ## Belongs to Finally, our Projects are going to get some Tasks. Then you create a `TasksController` and do: ```ruby class TasksController < InheritedResources::Base belongs_to :project end ``` `belongs_to` accepts several options to be able to configure the association. For example, if you want urls like "/projects/:project_title/tasks", you can customize how InheritedResources find your projects: ```ruby class TasksController < InheritedResources::Base belongs_to :project, :finder => :find_by_title!, :param => :project_title end ``` It also accepts `:route_name`, `:parent_class` and `:instance_name` as options. Check the [lib/inherited_resources/class_methods.rb](https://github.com/activeadmin/inherited_resources/blob/master/lib/inherited_resources/class_methods.rb) for more. ## Nested belongs to Now, our Tasks get some Comments and you need to nest even deeper. Good practices says that you should never nest more than two resources, but sometimes you have to for security reasons. So this is an example of how you can do it: ```ruby class CommentsController < InheritedResources::Base nested_belongs_to :project, :task end ``` If you need to configure any of these belongs to, you can nest them using blocks: ```ruby class CommentsController < InheritedResources::Base belongs_to :project, :finder => :find_by_title!, :param => :project_title do belongs_to :task end end ``` Warning: calling several `belongs_to` is the same as nesting them: ```ruby class CommentsController < InheritedResources::Base belongs_to :project belongs_to :task end ``` In other words, the code above is the same as calling `nested_belongs_to`. ## Polymorphic belongs to We can go even further. Let's suppose our Projects can now have Files, Messages and Tasks, and they are all commentable. In this case, the best solution is to use polymorphism: ```ruby class CommentsController < InheritedResources::Base belongs_to :task, :file, :message, :polymorphic => true # polymorphic_belongs_to :task, :file, :message end ``` You can even use it with nested resources: ```ruby class CommentsController < InheritedResources::Base belongs_to :project do belongs_to :task, :file, :message, :polymorphic => true end end ``` The url in such cases can be: ``` /project/1/task/13/comments /project/1/file/11/comments /project/1/message/9/comments ``` When using polymorphic associations, you get some free helpers: ```ruby parent? #=> true parent_type #=> :task parent_class #=> Task parent #=> @task ``` Right now, Inherited Resources is limited and does not allow you to have two polymorphic associations nested. ## Optional belongs to Later you decide to create a view to show all comments, independent if they belong to a task, file or message. You can reuse your polymorphic controller just doing: ```ruby class CommentsController < InheritedResources::Base belongs_to :task, :file, :message, :optional => true # optional_belongs_to :task, :file, :message end ``` This will handle all those urls properly: ``` /comment/1 /tasks/2/comment/5 /files/10/comment/3 /messages/13/comment/11 ``` This is treated as a special type of polymorphic associations, thus all helpers are available. As you expect, when no parent is found, the helpers return: ```ruby parent? #=> false parent_type #=> nil parent_class #=> nil parent #=> nil ``` ## Singletons Now we are going to add manager to projects. We say that `Manager` is a singleton resource because a `Project` has just one manager. You should declare it as `has_one` (or resource) in your routes. To declare an resource of current controller as singleton, you just have to give the `:singleton` option in defaults. ```ruby class ManagersController < InheritedResources::Base defaults :singleton => true belongs_to :project # singleton_belongs_to :project end ``` So now you can use urls like "/projects/1/manager". In the case of nested resources (when some of the can be singletons) you can declare it separately ```ruby class WorkersController < InheritedResources::Base #defaults :singleton => true #if you have only single worker belongs_to :project belongs_to :manager, :singleton => true end ``` This is correspond urls like "/projects/1/manager/workers/1". It will deal with everything again and hide the action :index from you. ## Namespaced Controllers Namespaced controllers works out the box. ```ruby class Forum::PostsController < InheritedResources::Base end ``` Inherited Resources prioritizes the default resource class for the namespaced controller in this order: ``` Forum::Post ForumPost Post ``` ## URL Helpers When you use InheritedResources it creates some URL helpers. And they handle everything for you. :) ```ruby # /posts/1/comments resource_url # => /posts/1/comments/#{@comment.to_param} resource_url(comment) # => /posts/1/comments/#{comment.to_param} new_resource_url # => /posts/1/comments/new edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit edit_resource_url(comment) # => /posts/1/comments/#{comment.to_param}/edit collection_url # => /posts/1/comments parent_url # => /posts/1 # /projects/1/tasks resource_url # => /projects/1/tasks/#{@task.to_param} resource_url(task) # => /projects/1/tasks/#{task.to_param} new_resource_url # => /projects/1/tasks/new edit_resource_url # => /projects/1/tasks/#{@task.to_param}/edit edit_resource_url(task) # => /projects/1/tasks/#{task.to_param}/edit collection_url # => /projects/1/tasks parent_url # => /projects/1 # /users resource_url # => /users/#{@user.to_param} resource_url(user) # => /users/#{user.to_param} new_resource_url # => /users/new edit_resource_url # => /users/#{@user.to_param}/edit edit_resource_url(user) # => /users/#{user.to_param}/edit collection_url # => /users parent_url # => / ``` Those urls helpers also accepts a hash as options, just as in named routes. ```ruby # /projects/1/tasks collection_url(:page => 1, :limit => 10) #=> /projects/1/tasks?page=1&limit=10 ``` In polymorphic cases, you can also give the parent as parameter to `collection_url`. Another nice thing is that those urls are not guessed during runtime. They are all created when your application is loaded (except for polymorphic associations, that relies on Rails' `polymorphic_url`). ## Custom actions Since version 1.2, Inherited Resources allows you to define custom actions in controller: ```ruby class ButtonsController < InheritedResources::Base custom_actions :resource => :delete, :collection => :search end ``` This code creates delete and search actions in controller (they behaves like show and index actions accordingly). Also, it will produce `delete_resource_{path,url}` and `search_resources_{path,url}` url helpers. ## What about views? Sometimes just DRYing up the controllers is not enough. If you need to DRY up your views, check this Wiki page: https://github.com/activeadmin/inherited_resources/wiki/Views-Inheritance Notice that Rails 3.1 ships with view inheritance built-in. ## Some DSL For those DSL lovers, InheritedResources won't leave you alone. You can overwrite your success/failure blocks straight from your class binding. For it, you just need to add a DSL module to your application controller: ```ruby class ApplicationController < ActionController::Base include InheritedResources::DSL end ``` And then you can rewrite the last example as: ```ruby class ProjectsController < InheritedResources::Base update! do |success, failure| failure.html { redirect_to project_url(@project) } end end ``` ## Strong Parameters If your controller defines a method named `permitted_params`, InheritedResources will call it where it would normally call params. This allows for easy integration with the strong_parameters gem: ```ruby def permitted_params params.permit(:widget => [:permitted_field, :other_permitted_field]) end ``` Remember that if your field is sent by client to server as an array, you have to write `:permitted_field => []`, not just `:permitted_field`. Note that this doesn't work if you use strong_parameters' require method instead of permit, because whereas permit returns the entire sanitized parameter hash, require returns only the sanitized params below the parameter you required. If you need `params.require` you can do it like this: ```ruby def permitted_params {:widget => params.fetch(:widget, {}).permit(:permitted_field, :other_permitted_field)} end ``` Or better yet just override `#build_resource_params` directly: ```ruby def build_resource_params [params.fetch(:widget, {}).permit(:permitted_field, :other_permitted_field)] end ``` Instead you can stick to a standard Rails 4 notation (as rails scaffold generates) and write: ```ruby def widget_params params.require(:widget).permit(:permitted_field, :other_permitted_field) end ``` In such case you should remove #permitted_params method because it has greater priority. ## Bugs and Feedback If you discover any bugs, please describe it in the issues tracker, including Rails and InheritedResources versions. Questions are better handled on StackOverflow. MIT License. Copyright (c) 2009-2017 José Valim. inherited-resources-1.9.0/inherited_resources.gemspec0000644000175000017500000000603113470613050023653 0ustar utkarsh2102utkarsh2102######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: inherited_resources 1.9.0 ruby lib Gem::Specification.new do |s| s.name = "inherited_resources".freeze s.version = "1.9.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Jos\u00E9 Valim".freeze, "Rafael Mendon\u00E7a Fran\u00E7a".freeze] s.date = "2018-08-10" s.description = "Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important.".freeze s.files = ["MIT-LICENSE".freeze, "README.md".freeze, "app/controllers/inherited_resources/base.rb".freeze, "lib/generators/rails/USAGE".freeze, "lib/generators/rails/inherited_resources_controller_generator.rb".freeze, "lib/generators/rails/templates/controller.rb".freeze, "lib/inherited_resources.rb".freeze, "lib/inherited_resources/actions.rb".freeze, "lib/inherited_resources/base_helpers.rb".freeze, "lib/inherited_resources/belongs_to_helpers.rb".freeze, "lib/inherited_resources/blank_slate.rb".freeze, "lib/inherited_resources/class_methods.rb".freeze, "lib/inherited_resources/dsl.rb".freeze, "lib/inherited_resources/engine.rb".freeze, "lib/inherited_resources/polymorphic_helpers.rb".freeze, "lib/inherited_resources/responder.rb".freeze, "lib/inherited_resources/shallow_helpers.rb".freeze, "lib/inherited_resources/singleton_helpers.rb".freeze, "lib/inherited_resources/url_helpers.rb".freeze, "lib/inherited_resources/version.rb".freeze] s.homepage = "http://github.com/activeadmin/inherited_resources".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3".freeze) s.rubyforge_project = "inherited_resources".freeze s.rubygems_version = "2.7.6.2".freeze s.summary = "Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important.".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q.freeze, ["< 5.3", ">= 4.2"]) s.add_runtime_dependency(%q.freeze, ["~> 0.6"]) s.add_runtime_dependency(%q.freeze, ["< 5.3", ">= 4.2"]) s.add_runtime_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, ["< 5.3", ">= 4.2"]) s.add_dependency(%q.freeze, ["~> 0.6"]) s.add_dependency(%q.freeze, ["< 5.3", ">= 4.2"]) s.add_dependency(%q.freeze, [">= 0"]) end else s.add_dependency(%q.freeze, ["< 5.3", ">= 4.2"]) s.add_dependency(%q.freeze, ["~> 0.6"]) s.add_dependency(%q.freeze, ["< 5.3", ">= 4.2"]) s.add_dependency(%q.freeze, [">= 0"]) end end