module Her module Model module Paths extend ActiveSupport::Concern # Return a path based on the collection path and a resource data # # @example # class User # include Her::Model # collection_path "/utilisateurs" # end # # User.find(1) # Fetched via GET /utilisateurs/1 # # @param [Hash] params An optional set of additional parameters for # path construction. These will not override attributes of the resource. def request_path(params = {}) self.class.build_request_path(params.merge(attributes.dup)) end module ClassMethods # Define the primary key field that will be used to find and save records # # @example # class User # include Her::Model # primary_key 'UserId' # end # # @param [Symbol] value def primary_key(value = nil) @_her_primary_key ||= begin superclass.primary_key if superclass.respond_to?(:primary_key) end return @_her_primary_key unless value @_her_primary_key = value.to_sym end # Defines a custom collection path for the resource # # @example # class User # include Her::Model # collection_path "/users" # end def collection_path(path = nil) if path.nil? @_her_collection_path ||= root_element.to_s.pluralize else @_her_collection_path = path @_her_resource_path = "#{path}/:id" end end # Defines a custom resource path for the resource # # @example # class User # include Her::Model # resource_path "/users/:id" # end # # Note that, if used in combination with resource_path, you may specify # either the real primary key or the string ':id'. For example: # # @example # class User # include Her::Model # primary_key 'user_id' # # # This works because we'll have a user_id attribute # resource_path '/users/:user_id' # # # This works because we replace :id with :user_id # resource_path '/users/:id' # end # def resource_path(path = nil) if path.nil? @_her_resource_path ||= "#{root_element.to_s.pluralize}/:id" else @_her_resource_path = path end end # Return a custom path based on the collection path and variable parameters # # @private def build_request_path(path = nil, parameters = {}) parameters = parameters.try(:with_indifferent_access) unless path.is_a?(String) parameters = path.try(:with_indifferent_access) || parameters path = if parameters.include?(primary_key) && parameters[primary_key] && !parameters[primary_key].is_a?(Array) resource_path.dup else collection_path.dup end # Replace :id with our actual primary key path.gsub!(/(\A|\/):id(\Z|\/)/, "\\1:#{primary_key}\\2") end path.gsub(/:([\w_]+)/) do # Look for :key or :_key, otherwise raise an exception key = $1.to_sym value = parameters.delete(key) || parameters.delete(:"_#{key}") if value Faraday::Utils.escape value else raise(Her::Errors::PathError.new("Missing :_#{$1} parameter to build the request path. Path is `#{path}`. Parameters are `#{parameters.symbolize_keys.inspect}`.", $1)) end end end # @private def build_request_path_from_string_or_symbol(path, params = {}) path.is_a?(Symbol) ? "#{build_request_path(params)}/#{path}" : path end end end end end