Rails validating search params

I have an API which is fairly restful but am struggling to work out how to implement a search cleanly. I want to be able to search for all the records between two date-times, the date-times are allowed to be a maximum of 6 hours apart. At the moment in my controller method I have the following:

required_params = [:start_time, :end_time]
if check_required_params(required_params, params) and check_max_time_bound(params, 6.hours)
   ... rest of controller code here ...
end

check_required_params is an application method that looks like this:

def check_required_params(required_params, params_sent)
required_params.each do |param|
  unless has_param(param, params_sent)
    unprocessable_entity
    return false
  end
end
  true
end

check_max_time is fairly similar.

I know it's against best practices to do validation in the controller but I can't see how I can add it to the model cleanly.

Answers


Actually what you are doing is (almost) best practice and will (almost) be incorporated in Rails 4 with strong parametsers. (I say almost because your check_max_time looks like it should be a validation in your model.)

You should go ahead and pull in the feature today and make upgrades easier on yourself. Strong Parameters https://github.com/rails/strong_parameters

Documentation is there, but here is how you incorporate it.

class SearchController < ApplicationController
  include ActiveModel::ForbiddenAttributesProtection

  def create
    # Doesn't have to be an ActiveRecord model
    @results = Search.create(search_params)
    respond_with @results
  end

  private

  def search_params
    # This will ensure that you have :start_time and :end_time, but will allow :foo and :bar
    params.require(:start_time, :end_time).permit(:foo, :bar #, whatever else)
  end
end

class Search < ActiveRecord::Base
  validates :time_less_than_six_hours

  private

  def time_less_than_six_hours
    errors.add(:end_time, "should be less than 6 hours from start") if (end_time - start_time) > 6.hours
  end
end

Never found a clean answer for this. However if you're making an API Grape has inbuilt Parameter Validation and Coercion to take care of it.


Well, what I would do in this scenario is the set the default value between these two datetimes so that i won't have to do validation and raise the exception.

class SearchController < ApplicationController
  before_filter :assign_default_params

  def index
  end

  private
  def assign_default_params
    params[:start_time] ||= Time.now
    params[:end_time]   ||= params[:start_time] + 6.hours
    params[:end_time]     = params[:start_time] + 6.hours if ((params[:end_time] - params[:start_time]) / 3600).round) > 6
  end
end

With this code above, it always has the params required to the search. The method assign_default_params try to assign default values if they are not sent from the clients. The last thing it does is that it assign params[:end_time] to a maximum value.

It's much neater because we don't have to do validation and the client won't need to handle different response code such as 422. And you should have an API documentation, stating about this fact as well.


Need Your Help

Values sorted as String but I want to sort them as number in Python

python sorting python-3.x

I read in python a log that contains name, memory, ncalls for each row