Skip to content

Commit

Permalink
doc(models_controller): update and clear doc. Add Rdoc rake task
Browse files Browse the repository at this point in the history
  • Loading branch information
paulRbr committed Aug 23, 2014
1 parent 5a3f1c3 commit 3e648f6
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 49 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
.idea
*~
coverage/
html/
7 changes: 7 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -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"]
Expand Down
120 changes: 71 additions & 49 deletions lib/yodatra/models_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,49 @@ module Yodatra
# Simply create your controller that inherits from this class, keeping the naming convention.
#
# For example, given a <b>User</b> model, creating a <b>class UsersController < Yodatra::ModelsController</b>, it will expose these routes:
# GET /users
# => retrieves all users <i>(attributes exposed are limited by the <b>read_scope</b> method defined in the <b>UsersController</b>)</i>
#
# GET /users/:id
# => retrieves a user <i>(attributes exposed are limited by the <b>read_scope</b> method defined in the <b>UsersController</b>)</i>
# GET /users
# > retrieves all users <i>(attributes exposed are limited by the <b>read_scope</b> method defined in the <b>UsersController</b>)</i>
#
# POST /users
# => creates a user <i>(attributes assignable are limited by the <b>user_params</b> method defined in the <b>UsersController</b>)</i>
# GET /users/:id
# > retrieves a user <i>(attributes exposed are limited by the <b>read_scope</b> method defined in the <b>UsersController</b>)</i>
#
# PUT /users/:id
# => updates a user <i>(attributes assignable are limited by the <b>user_params</b> method defined in the <b>UsersController</b>)</i>
# POST /users
# > creates a user <i>(attributes assignable are limited by the <b>user_params</b> method defined in the <b>UsersController</b>)</i>
#
# DELETE /users/:id
# => deletes a user
# PUT /users/:id
# > updates a user <i>(attributes assignable are limited by the <b>user_params</b> method defined in the <b>UsersController</b>)</i>
#
# 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 <b>Team</b> model that has many <b>User</b>s, 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 <b>::disable</b> 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 <b>#enable_search_on</b> 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|
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 3e648f6

Please sign in to comment.