Module: MergeParams::Helpers
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/merge_params/helpers.rb
Instance Method Summary collapse
-
#add_params(url = request.fullpath, new_params = {}) ⇒ Object
Adds params to the query string (Unlike url_for_merge, which tries to generate a route from the params.).
-
#merge_params(new_params = {}) ⇒ Object
Safely merges the given params with the params from the current request.
-
#merge_url_for(new_params = {}) ⇒ Object
Safely merges the given params with the params from the current request, then generates a route from the merged params.
-
#params_for_url_for(params = params()) ⇒ Object
Params that can safely be passed to url_for to build a route.
-
#params_from_url(url) ⇒ Object
Parsing helpers.
- #parse_nested_query(query) ⇒ Object
-
#query_params ⇒ Object
Returns a hash of params from the query string (en.wikipedia.org/wiki/Query_string), with symbolized keys.
-
#query_params_from_request_params ⇒ Object
request.parameters (which also includes POST params) but with only those keys that would normally be passed in a query string (without :controller, :action, :format) and with symbolized keys.
-
#request_params ⇒ Object
request.parameters but with symbolized keys.
-
#slice_params(*keys) ⇒ Object
Easily extract just certain param keys.
Instance Method Details
#add_params(url = request.fullpath, new_params = {}) ⇒ Object
Adds params to the query string (Unlike url_for_merge, which tries to generate a route from the params.)
112 113 114 115 116 117 118 119 120 |
# File 'lib/merge_params/helpers.rb', line 112 def add_params(url = request.fullpath, new_params = {}) uri = URI(url) # Allow keys that are currently in query_params to be deleted by setting their value to nil in # new_params (including in nested hashes). merged_params = parse_nested_query(uri.query || ''). deep_merge(new_params).recurse(&:compact) uri.query = Rack::Utils.build_nested_query(merged_params).presence uri.to_s end |
#merge_params(new_params = {}) ⇒ Object
Safely merges the given params with the params from the current request
59 60 61 62 |
# File 'lib/merge_params/helpers.rb', line 59 def merge_params(new_params = {}) params_for_url_for. deep_merge(new_params.deep_symbolize_keys) end |
#merge_url_for(new_params = {}) ⇒ Object
Safely merges the given params with the params from the current request, then generates a route from the merged params. You can remove a key by passing nil as the value, for example nil.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/merge_params/helpers.rb', line 90 def merge_url_for(new_params = {}) url = url_for(merge_params(new_params)) # # Now pass along in the *query string* any params that we couldn't pass to url_for because they # # were reserved options. # query_params_already_added = parse_nested_query(URI(url).query || '') # # Some params from new_params (like company_id) that we pass in may be recognized by a route and # # therefore no longer be query params. We use recognize_path to find those params that ended up # # as route params instead of query_params but are nonetheless already added to the url. # params_already_added = Rails.application.routes.recognize_path(url).merge(query_params_already_added) params_already_added = params_from_url(url) query_params_to_add = params_for_url_for(new_params). recursively_comparing(params_already_added).graph { |k,v, other| if v.is_a?(Hash) || v.nil? || other.nil? [k, v] end } add_params(url, query_params_to_add) end |
#params_for_url_for(params = params()) ⇒ Object
Params that can safely be passed to url_for to build a route. (Used by merge_url_for.)
We exclude RESERVED_OPTIONS such as :host because such options should only come from your app code. Allowing :host to be set via query params, for example, means a bad actor could cause links that go to a different site entirely:
# Request for /things?host=somehackingsite.ru url_for(params) => “somehackingsite.ru/things”
Similarly, the :controller and :action keys of ‘params` never come from the query string, but from `path_parameters`. (TODO: So why not just use params.except(…)?)
TODO: Why not allow :format from params? To force people to use .:format? But doesn’t that also come through as params?
(And we don’t even need to pass the path_parameters on to url_for because url_for already includes those (from :_recall)
48 49 50 51 52 53 54 55 56 |
# File 'lib/merge_params/helpers.rb', line 48 def params_for_url_for(params = params()) params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h) params.deep_symbolize_keys.except( *ActionDispatch::Routing::RouteSet::RESERVED_OPTIONS, :controller, :action, :format ) end |
#params_from_url(url) ⇒ Object
Parsing helpers
133 134 135 136 137 138 139 |
# File 'lib/merge_params/helpers.rb', line 133 def params_from_url(url) query_params = parse_nested_query(URI(url).query || '') route_params = Rails.application.routes.recognize_path(url.to_s) params_for_url_for( route_params.merge(query_params) ) end |
#parse_nested_query(query) ⇒ Object
141 142 143 |
# File 'lib/merge_params/helpers.rb', line 141 def parse_nested_query(query) Rack::Utils.parse_nested_query(query || '').deep_symbolize_keys end |
#query_params ⇒ Object
Returns a hash of params from the query string (en.wikipedia.org/wiki/Query_string), with symbolized keys.
26 27 28 |
# File 'lib/merge_params/helpers.rb', line 26 def query_params request.query_parameters.deep_symbolize_keys end |
#query_params_from_request_params ⇒ Object
request.parameters (which also includes POST params) but with only those keys that would normally be passed in a query string (without :controller, :action, :format) and with symbolized keys.
19 20 21 22 |
# File 'lib/merge_params/helpers.rb', line 19 def query_params_from_request_params request.parameters.deep_symbolize_keys. except(*request.path_parameters.deep_symbolize_keys.keys) end |
#request_params ⇒ Object
request.parameters but with symbolized keys.
12 13 14 |
# File 'lib/merge_params/helpers.rb', line 12 def request_params request.parameters.deep_symbolize_keys end |
#slice_params(*keys) ⇒ Object
Easily extract just certain param keys.
Can’t use permit().to_h — for example,
params.permit(:page, :per_page, :filters).to_h
or you’ll get an error about whatever other unrelated keys happen to be set:
found unpermitted parameters: :utf8, :commit, :company_id
One good solution might be to have a permitted_params method defined with all of your permitted params for this controller, and then you could make other methods that fetch subsets of those params using slice. But if you don’t want to do that, this slice_params helper is another good option.
Other options include:
-
You could add those unrelated keys to always_permitted_parameters … but that only works if all of them should be permitted everywhere — there are probably controller-specific params present that are permitted for this controller.
-
You could also change action_on_unpermitted_parameters — but unfortunately, there’s no way to pass a temporary override value for that directly to permit, so the only option is to change it temporarily globally, which is inconvenient and not thread-safe.
83 84 85 |
# File 'lib/merge_params/helpers.rb', line 83 def slice_params(*keys) params_for_url_for.slice(*keys) end |