1

I want to redirect to 404 if request url contains invalid parameters, but I did not know what is the best way to achieve that. For example: The request url: http://example.com/a_path/?invalid_parameter=foo In this case, I want rails return 404. My stupid way is iterating params and check if contains invalided keys:

def redirect_404_if_invalid_params
  valid_params = [:valid_key_1, :valid_key_2, :valid_key_3]
  params.each do |key, value|
    if !valid_params.include?(key)
      redirect 404
    end
  end
end

But is there any better way to do this trick? Thanks.

timlentse
  • 195
  • 2
  • 11
  • With this code you'll redirect if there's a _valid_ parameter :) – Sergio Tulentsev Nov 11 '15 at 06:18
  • I want my url is clean, which is seo friendly. And 404 is enough, I don't need render something. – timlentse Nov 11 '15 at 06:27
  • Ah, it seems that you're totally misguided here, my friend. Assuming this is true (clean urls are favored more by search engines), this redirect improves nothing! Search engines index pages and evaluate links in them. They do not watch your site to see if it accepts dirty urls or not. So on your pages render clean nice urls. And pages you don't control - well, you don't control them, they can post links in whichever format they want. In either case, this redirect is useless. – Sergio Tulentsev Nov 11 '15 at 06:35

3 Answers3

2

You can use Strong Parameters to filter out the parameters you don't want in an action. To do this, you would have to set:

ActionController::Parameters.action_on_unpermitted_parameters = :raise

so Strong Parameters fails whenever you receive parameters that are not explicitly allowed. Then, specify the parameters you do want to be available, like:

def valid_params
  params.require(:param_a).permit(:attr_a, :attr_b)
end

And consume your parameters like valid_params[:attr_a], instead of referencing params directly.

You can catch ActionController::UnpermittedParameters and throw your 404 accordingly or do anything else you may need, though I don't suggest you to this. 404 is the HTTP error for "Not Found", having invalid parameters sound more like 422, "Unprocessable Entity".

Heldraug
  • 256
  • 1
  • 3
  • 10
1

Assuming that you want to do exactly that for some reason, here's a compact way.

valid_params = [:valid_key_1, :valid_key_2, :valid_key_3]

if (params.keys - valid_params.map(&:to_s)).present?
  not_found
end

Take all params, remove all known valid params. If there's something left, it must be invalid keys. In which case, raise.

BTW, not_found in code above is defined as shown in this answer.

Although, for most cases this is not needed and strong parameters should be used instead. With strong parameters it's another approach: we don't care about unknown parameters, we extract only known good parameters and discard the rest.

Community
  • 1
  • 1
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
1

I had this same problem and researched extensively. This was my solution: In my application_controller.rb I did this:

rescue_from ActiveRecord::RecordNotFound, with: :not_found 
rescue_from Exception, with: :not_found
rescue_from ActionController::RoutingError, with: :not_found

def raise_not_found     
   raise ActionController::RoutingError.new("No route matches # {params[:unmatched_route]}")
end

def not_found
  respond_to do |format|
   format.html { render :file => "#{Rails.root}/public/404", :layout =>  false, :status => :not_found }
   format.xml { head :not_found }
   format.any { head :not_found }
  end
end

And then in your routes.rb file do this:

get '*unmatched_route', to: 'application#raise_not_found'

What does the code do.

You probably have an idea what the rescue_from code line of code does.

raise_not_found if for the line of code you put in the routes file. This method triggers the RoutingError and when this happens, not_found is called.

Any url that does not exit in your routes file would yield the 404.html page.

mrtorks
  • 66
  • 2
  • 11