diff --git a/.gitignore b/.gitignore
index 6a01cab..47b61c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
.idea
*~
coverage/
+html/
diff --git a/Rakefile b/Rakefile
index fa9a284..24088b3 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,5 +1,12 @@
require 'rubygems'
+
+require 'rdoc/task'
+RDoc::Task.new do |rdoc|
+ rdoc.main = "README.md"
+ rdoc.rdoc_files.include("README.md", "lib/**/*.rb")
+end
+
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new do |task|
task.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
diff --git a/lib/yodatra/models_controller.rb b/lib/yodatra/models_controller.rb
index e355042..f59204f 100644
--- a/lib/yodatra/models_controller.rb
+++ b/lib/yodatra/models_controller.rb
@@ -5,48 +5,49 @@ module Yodatra
# Simply create your controller that inherits from this class, keeping the naming convention.
#
# For example, given a User model, creating a class UsersController < Yodatra::ModelsController, it will expose these routes:
- # GET /users
- # => retrieves all users (attributes exposed are limited by the read_scope method defined in the UsersController)
#
- # GET /users/:id
- # => retrieves a user (attributes exposed are limited by the read_scope method defined in the UsersController)
+ # GET /users
+ # > retrieves all users (attributes exposed are limited by the read_scope method defined in the UsersController)
#
- # POST /users
- # => creates a user (attributes assignable are limited by the user_params method defined in the UsersController)
+ # GET /users/:id
+ # > retrieves a user (attributes exposed are limited by the read_scope method defined in the UsersController)
#
- # PUT /users/:id
- # => updates a user (attributes assignable are limited by the user_params method defined in the UsersController)
+ # POST /users
+ # > creates a user (attributes assignable are limited by the user_params method defined in the UsersController)
#
- # DELETE /users/:id
- # => deletes a user
+ # PUT /users/:id
+ # > updates a user (attributes assignable are limited by the user_params method defined in the UsersController)
+ #
+ # DELETE /users/:id
+ # > deletes a user
#
# If your model is referenced by another model, nested routes are also created for you. And you don't need to worry about the references/joins, they are done automaticly!
# For example, imagine a Team model that has many Users, the following routes will be exposed:
- # GET /team/:team_id/users, GET /team/:team_id/users/:id, POST /team/:team_id/users, PUT /team/:team_id/users/:id and DESTROY /team/:team_id/users/:id
#
- # _Note_: You can disable any of these five actions by using the `#disable` class method
- # and giving in parameters the list of actions you want to disable
- # e.g. `disable :read, :read_all, :create, :update, :delete`
+ # GET /team/:team_id/users
+ #
+ # GET /team/:team_id/users/:id
+ #
+ # POST /team/:team_id/users
+ #
+ # PUT /team/:team_id/users/:id
+ #
+ # DESTROY /team/:team_id/users/:id
#
- # _Note2_: You can enable a special "search" action by using the `#enable_search_on` class method
+ # === Note:
+ # You can disable any of these actions by using the ::disable class method
+ # and providing the list of actions you want to disable
+ # disable :read, :read_all, :create, :update, :delete, :nested_read_all, :nested_delete
+ #
+ # === Extra:
+ # You can enable a special "search" action by using the #enable_search_on class method
+ # enable_search_on :name
class ModelsController < Sinatra::Base
before do
content_type 'application/json'
end
- # Generic route to target ONE resource
- ONE_ROUTE =
- %r{\A/([\w]+?)/([0-9]+)(?:/([\w]+?)/([0-9]+)){0,1}\Z}
-
- # Generic route to target ALL resources
- ALL_ROUTE =
- %r{\A/([\w]+?)(?:/([0-9]+)/([\w]+?)){0,1}\Z}
-
- # Search route
- SEARCH_ROUTE =
- %r{\A/([\w]+?)(?:/([0-9]+)/([\w]+?)){0,1}/search\Z}
-
READ_ALL = :read_all
get ALL_ROUTE do
retrieve_resources READ_ALL do |resource|
@@ -101,29 +102,9 @@ class ModelsController < Sinatra::Base
end
end
- # Defines a nested route or not and retrieves the correct resource (or resources)
- # @param disables is the name to check if it was disabled
- # @param &block to be yield with the retrieved resource
- def retrieve_resources(disables)
- pass unless involved?
- no_route if disabled? disables
-
- model = model_name.constantize
- nested = nested_resources if nested?
-
- if model.nil? || nested.nil? && nested?
- raise ActiveRecord::RecordNotFound
- else
- model = nested if nested?
- one_id = nested? ? params[:captures].fourth : params[:captures].second if params[:captures].length == 4
- model = model.find one_id unless one_id.nil?
- yield(model)
- end
- rescue ActiveRecord::RecordNotFound
- record_not_found
- end
-
class << self
+ private
+
def model_name
self.name.split('::').last.gsub(/sController/, '')
end
@@ -132,6 +113,8 @@ def model
model_name.constantize
end
+ public
+
# This helper gives the ability to disable default root by specifying
# a list of routes to disable.
# @param *opts list of routes to disable (e.g. :create, :destroy)
@@ -143,6 +126,11 @@ def disable(*opts)
end
end
+ # This class method enables the search routes `/resoures/search?q=search+terms` for the model.
+ # The search will be performed on all the attributes given in parameter of this method.
+ # E.g. if you enabled the search on `:name` and `:email` attrs
+ # a GET /resources/search?q=john+doe
+ # will return all `Resource` instance where the name or the email matches either "john" or "doe"
def enable_search_on(*attributes)
self.instance_eval do
get SEARCH_ROUTE do
@@ -170,6 +158,40 @@ def enable_search_on(*attributes)
private
+ # Generic route to target ONE resource
+ ONE_ROUTE =
+ %r{\A/([\w]+?)/([0-9]+)(?:/([\w]+?)/([0-9]+)){0,1}\Z}
+
+ # Generic route to target ALL resources
+ ALL_ROUTE =
+ %r{\A/([\w]+?)(?:/([0-9]+)/([\w]+?)){0,1}\Z}
+
+ # Search route
+ SEARCH_ROUTE =
+ %r{\A/([\w]+?)(?:/([0-9]+)/([\w]+?)){0,1}/search\Z}
+
+ # Defines a nested route or not and retrieves the correct resource (or resources)
+ # @param disables is the name to check if it was disabled
+ # @param &block to be yield with the retrieved resource
+ def retrieve_resources(disables)
+ pass unless involved?
+ no_route if disabled? disables
+
+ model = model_name.constantize
+ nested = nested_resources if nested?
+
+ if model.nil? || nested.nil? && nested?
+ raise ActiveRecord::RecordNotFound
+ else
+ model = nested if nested?
+ one_id = nested? ? params[:captures].fourth : params[:captures].second if params[:captures].length == 4
+ model = model.find one_id unless one_id.nil?
+ yield(model)
+ end
+ rescue ActiveRecord::RecordNotFound
+ record_not_found
+ end
+
def nested?
params[:captures].length >= 3 && params[:captures].first(3).none?(&:nil?)
end