moduleInheritedResources# = 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.#moduleUrlHelpers# 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.#defcreate_resources_url_helpers!resource_segments,resource_ivars=[],[]resource_config=self.resources_configuration[:self]singleton=self.resources_configuration[:self][:singleton]polymorphic=self.parents_symbols.include?(:polymorphic)# Add route_prefix if any.unlessresource_config[:route_prefix].blank?ifpolymorphicresource_ivars<<resource_config[:route_prefix].to_s.inspectelseresource_segments<<resource_config[:route_prefix]endend# 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.eachdo|symbol|ifsymbol==:polymorphicresource_ivars<<:parentelseconfig=self.resources_configuration[symbol]resource_segments<<config[:route_name]resource_ivars<<:"@#{config[:instance_name]}"endendcollection_ivars=resource_ivars.dupcollection_segments=resource_segments.dup# Generate parent url before we add resource instances.unlessparents_symbols.empty?generate_url_and_path_helpersnil,:parent,resource_segments,resource_ivarsgenerate_url_and_path_helpers:edit,:parent,resource_segments,resource_ivarsend# 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.#ifsingletoncollection_segments.popresource_ivars.popifpolymorphicresource_ivars<<resource_config[:instance_name].inspectnew_ivars=resource_ivarsendelsifpolymorphiccollection_ivars<<'(@_resource_class_new ||= resource_class.new)'endgenerate_url_and_path_helpersnil,:collection,collection_segments,collection_ivarsgenerate_url_and_path_helpers:new,:resource,resource_segments,new_ivars||collection_ivarsgenerate_url_and_path_helpersnil,:resource,resource_segments,resource_ivarsgenerate_url_and_path_helpers:edit,:resource,resource_segments,resource_ivarsenddefgenerate_url_and_path_helpers(prefix,name,resource_segments,resource_ivars)#:nodoc:ivars=resource_ivars.dupsingleton=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==:newivars.push"(given_args.first || #{ivars.pop})"end# In collection in polymorphic cases, allow an argument to be given as a# replacemente for the parent.#ifname==:collection&&polymorphicindex=ivars.index(:parent)ivars.insertindex,"(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.#ifpolymorphicsegments=:polymorphicivars="[#{ivars.join(', ')}]"ivars<<'.compact'ifself.resources_configuration[:polymorphic][:optional]elsesegments=resource_segments.empty??'root':resource_segments.join('_')ivars=ivars.join(', ')endprefix=prefix?"#{prefix}_":''ivars<<(ivars.empty??'given_options':', given_options')class_eval<<-URL_HELPERS,__FILE__,__LINE__
protected
def #{prefix}#{name}_path(*given_args)
given_options = given_args.extract_options!
#{prefix}#{segments}_path(#{ivars})
end
def #{prefix}#{name}_url(*given_args)
given_options = given_args.extract_options!
#{prefix}#{segments}_url(#{ivars})
end
URL_HELPERSendendend