Module: ApiHammer::Rails
- Includes:
- HaltMethods
- Defined in:
- lib/api_hammer/halt.rb,
lib/api_hammer/rails.rb,
lib/api_hammer/check_required_params.rb,
lib/api_hammer/unmunged_request_params.rb
Defined Under Namespace
Modules: HaltMethods
Class Method Summary collapse
Instance Method Summary collapse
-
#check_required_params(*checks) ⇒ Object
halts with a 422 Unprocessable Entity and an appropriate error body if required params are missing .
-
#find_or_halt(model, find_attrs, options = {}) ⇒ Object
attempts to find and return the given model (an ActiveRecord::Base subclass) with the given attributes.
-
#halt(status, body, render_options = {}) ⇒ Object
halt and render the given body.
-
#halt_error(status, errors, options = {}) ⇒ Object
halt and render the given errors in the body on the 'errors' key.
-
#handle_halt(halt) ⇒ Object
handle a raised ApiHammer::Halt or subclass and render it.
-
#unmunged_request_params ⇒ Object
request parameters (not query parameters) without the nil/empty array munging that rails does.
Methods included from HaltMethods
#halt_accepted, #halt_already_reported, #halt_authentication_timeout, #halt_bad_gateway, #halt_bad_request, #halt_bandwidth_limit_exceeded, #halt_conflict, #halt_created, #halt_expectation_failed, #halt_failed_dependency, #halt_forbidden, #halt_found, #halt_gateway_timeout, #halt_gone, #halt_http_version_not_supported, #halt_im_a_teapot, #halt_im_used, #halt_insufficient_storage, #halt_internal_server_error, #halt_length_required, #halt_locked, #halt_loop_detected, #halt_method_not_allowed, #halt_moved_permanently, #halt_multi_status, #halt_multiple_choices, #halt_network_authentication_required, #halt_no_content, #halt_no_response, #halt_non_authoritative_information, #halt_not_acceptable, #halt_not_extended, #halt_not_found, #halt_not_implemented, #halt_not_modified, #halt_ok, #halt_partial_content, #halt_payment_required, #halt_permanent_redirect, #halt_precondition_failed, #halt_precondition_required, #halt_proxy_authentication_required, #halt_redirect, #halt_request_entity_too_large, #halt_request_header_fields_too_large, #halt_request_timeout, #halt_request_uri_too_long, #halt_requested_range_not_satisfiable, #halt_reset_content, #halt_see_other, #halt_service_unavailable, #halt_temporary_redirect, #halt_too_many_requests, #halt_unauthorized, #halt_unavailable_for_legal_reasons, #halt_unordered_collection, #halt_unprocessable_entity, #halt_unsupported_media_type, #halt_upgrade_required, #halt_use_proxy, #halt_variant_also_negotiates
Class Method Details
.included(klass) ⇒ Object
6 7 8 9 10 |
# File 'lib/api_hammer/rails.rb', line 6 def self.included(klass) (@on_included || []).each do |included_proc| included_proc.call(klass) end end |
Instance Method Details
#check_required_params(*checks) ⇒ Object
halts with a 422 Unprocessable Entity and an appropriate error body if required params are missing
simple:
check_required_params(:id, :name)
params[:id]must be presentparams[:name]must be present
less simple:
check_required_params(:id, :person => [:name, :height], :lucky_numbers => Array)
params[:id]must be presentparams[:person]must be present and be a hashparams[:person][:name]must be presentparams[:person][:height]must be presentparams[:lucky_numbers]must be present and be an array
20 21 22 23 24 |
# File 'lib/api_hammer/check_required_params.rb', line 20 def check_required_params(*checks) errors = Hash.new { |h,k| h[k] = [] } check_required_params_helper(checks, params, errors, []) halt_unprocessable_entity(errors) if errors.any? end |
#find_or_halt(model, find_attrs, options = {}) ⇒ Object
attempts to find and return the given model (an ActiveRecord::Base subclass) with the given attributes. halts with 404 (does not return) if that fails. options[:status] may specify a different status if that is required.
e.g.:
find_or_halt(User, :email => '[email protected]')
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/api_hammer/halt.rb', line 81 def find_or_halt(model, find_attrs, ={}) = {:status => 404}.merge() record = model.where(find_attrs).first unless record attributes = find_attrs.map{|attr, val| "#{attr}: #{val}" }.join(", ") model_name = model.table_name model_name = model_name.singularize if model_name.respond_to?(:singularize) = I18n.t(:"errors.unknown_record_with_attributes", :default => "Unknown %{model_name}! %{attributes}", :model_name => model_name, :attributes => attributes ) halt_error([:status], {model_name => []}) end record end |
#halt(status, body, render_options = {}) ⇒ Object
halt and render the given body
42 43 44 |
# File 'lib/api_hammer/halt.rb', line 42 def halt(status, body, = {}) raise(ApiHammer::Halt.new(body.inspect, body, .merge(:status => status))) end |
#halt_error(status, errors, options = {}) ⇒ Object
halt and render the given errors in the body on the 'errors' key
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/api_hammer/halt.rb', line 47 def halt_error(status, errors, = {}) errors_as_json = errors.respond_to?(:as_json) ? errors.as_json : errors unless errors_as_json.is_a?(Hash) raise ArgumentError, "errors be an object representable in JSON as a Hash; got errors = #{errors.inspect}" end unless errors_as_json.keys.all? { |k| k.is_a?(String) || k.is_a?(Symbol) } raise ArgumentError, "errors keys must all be string or symbol; got errors = #{errors.inspect}" end unless errors_as_json.values.all? { |v| v.is_a?(Array) && v.all? { |e| e.is_a?(String) } } raise ArgumentError, "errors values must all be arrays of strings; got errors = #{errors.inspect}" end = .dup.with_indifferent_access body = {'errors' => errors} = .delete('error_message') || begin error_values = errors.values.inject([], &:+) if error_values.size <= 1 error_values.first else # sentencify with periods error_values.map { |v| v =~ /\.\s*\z/ ? v : v + '.' }.join(' ') end end body['error_message'] = if halt(status, body, ) end |
#handle_halt(halt) ⇒ Object
handle a raised ApiHammer::Halt or subclass and render it
30 31 32 33 34 35 36 37 38 39 |
# File 'lib/api_hammer/halt.rb', line 30 def handle_halt(halt) = halt. ? halt..dup : {} # rocket pants does not have a render method, just render_json if respond_to?(:render_json, true) render_json(halt.body || {}, ) else [:json] = halt.body || {} render() end end |
#unmunged_request_params ⇒ Object
request parameters (not query parameters) without the nil/empty array munging that rails does
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/api_hammer/unmunged_request_params.rb', line 3 def unmunged_request_params # Thread.exclusive is not optimal but we need to ensure that any other params parsing occurring in other # threads is not affected by disabling munging # # TODO when we are on a rails which has ActionDispatch::Request::Utils.perform_deep_munge, use that instead # of clobbering methods @unmunged_params ||= Thread.exclusive do unless ActionDispatch::Request.method_defined?(:real_deep_munge) ActionDispatch::Request.send(:alias_method, :real_deep_munge, :deep_munge) end ActionDispatch::Request.send(:define_method, :deep_munge) { |hash| hash } begin unmunged_params = nil newenv = request.env.merge('action_dispatch.request.request_parameters' => nil) ActionDispatch::ParamsParser.new(proc do |env| unmunged_params = env['action_dispatch.request.request_parameters'] end).call(newenv) unmunged_params || ActionDispatch::Request.new(newenv).request_parameters ensure ActionDispatch::Request.send(:alias_method, :deep_munge, :real_deep_munge) end end end |