constraints for routes is way to go, but I would suggest a bit different solution for your problem.
Consider creating custom Constraint objects, which will query the database in order to check if Post or Category exists:
app/lib/post_constraint.rb
class PostConstraint
  def matches?(request)
    Post.exists?(request[:id])
  end
end
app/lib/category_constraint.rb
class CategoryConstraint
  def matches?(request)
    Category.exists?(request[:id])
  end
end
In your app/config/routes.rb
get ":id" => "posts#show",      constraints: PostConstraint.new
get ":id" => "categories#show", constraints: CategoryConstraint.new
You have to be aware of the fact, that id is very poor candidate for such comparison, because the Post is checked in first place, and if there is record matching, the "posts#show" will be accessed, and CategoryConstraint wot be even bothered. 
For more, check the documentation.
You should consider adding a slug for both models to easier serve exactly what user expects to see. For this purpose, try gem friendly_id.
Hope that helps! Good luck!