问题
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.
回答1:
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
回答2:
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.
回答3:
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.
来源:https://stackoverflow.com/questions/10745814/rails-validating-search-params