instant-api 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +142 -0
- data/README.md +231 -0
- data/instant_api.gemspec +20 -0
- data/lib/instant_api.rb +13 -0
- data/lib/instant_api/controller/build_create.rb +34 -0
- data/lib/instant_api/controller/build_destroy.rb +23 -0
- data/lib/instant_api/controller/build_edit.rb +11 -0
- data/lib/instant_api/controller/build_index.rb +39 -0
- data/lib/instant_api/controller/build_new.rb +22 -0
- data/lib/instant_api/controller/build_resource.rb +29 -0
- data/lib/instant_api/controller/build_show.rb +25 -0
- data/lib/instant_api/controller/build_update.rb +46 -0
- data/lib/instant_api/controller/builder.rb +54 -0
- data/lib/instant_api/controller/exception_handler.rb +38 -0
- data/lib/instant_api/controller/parameters.rb +43 -0
- data/lib/instant_api/controller/routes.rb +46 -0
- data/lib/instant_api/model/active_record_query_builder.rb +36 -0
- data/lib/instant_api/model/association_reflector.rb +93 -0
- data/lib/instant_api/model/builder.rb +95 -0
- data/lib/instant_api/model/collection.rb +43 -0
- data/lib/instant_api/model/resource.rb +14 -0
- data/lib/instant_api/util/array.rb +15 -0
- data/lib/instant_api/version.rb +3 -0
- data/spec/dummy/Gemfile +58 -0
- data/spec/dummy/Gemfile.lock +193 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +16 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/a.rb +5 -0
- data/spec/dummy/app/models/address.rb +4 -0
- data/spec/dummy/app/models/b.rb +4 -0
- data/spec/dummy/app/models/c.rb +4 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/country.rb +4 -0
- data/spec/dummy/app/models/d.rb +3 -0
- data/spec/dummy/app/models/movie.rb +4 -0
- data/spec/dummy/app/models/user.rb +8 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +23 -0
- data/spec/dummy/config/boot.rb +4 -0
- data/spec/dummy/config/database.yml +39 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/instant_api.rb +3 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/migrate/20131019140756_create_users.rb +14 -0
- data/spec/dummy/db/migrate/20131019141942_create_addresses.rb +14 -0
- data/spec/dummy/db/migrate/20131020003152_a.rb +9 -0
- data/spec/dummy/db/migrate/20131020003245_b.rb +10 -0
- data/spec/dummy/db/migrate/20131020003354_c.rb +11 -0
- data/spec/dummy/db/migrate/20131020164202_d.rb +9 -0
- data/spec/dummy/db/migrate/20131020164349_ad.rb +8 -0
- data/spec/dummy/db/migrate/20140419205834_create_countries.rb +9 -0
- data/spec/dummy/db/migrate/20140421005321_create_movies.rb +8 -0
- data/spec/dummy/db/migrate/20140421005435_create_countries_movies.rb +8 -0
- data/spec/dummy/db/schema.rb +88 -0
- data/spec/dummy/db/seeds.rb +7 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/lib/tasks/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/robots.txt +5 -0
- data/spec/dummy/vendor/assets/javascripts/.keep +0 -0
- data/spec/dummy/vendor/assets/stylesheets/.keep +0 -0
- data/spec/factories/address_factory.rb +8 -0
- data/spec/factories/country_factory.rb +5 -0
- data/spec/factories/movies_factory.rb +5 -0
- data/spec/factories/user_factory.rb +10 -0
- data/spec/functional/create_spec.rb +16 -0
- data/spec/functional/destroy_spec.rb +21 -0
- data/spec/functional/edit_spec.rb +19 -0
- data/spec/functional/index_spec.rb +82 -0
- data/spec/functional/new_spec.rb +14 -0
- data/spec/functional/show_spec.rb +20 -0
- data/spec/functional/update_spec.rb +47 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/database_cleaner.rb +20 -0
- data/spec/support/helpers.rb +31 -0
- data/spec/unit/lib/instant_api/controller/build_create_spec.rb +38 -0
- data/spec/unit/lib/instant_api/controller/build_destroy_spec.rb +25 -0
- data/spec/unit/lib/instant_api/controller/build_edit_spec.rb +24 -0
- data/spec/unit/lib/instant_api/controller/build_index_spec.rb +49 -0
- data/spec/unit/lib/instant_api/controller/build_new_spec.rb +18 -0
- data/spec/unit/lib/instant_api/controller/build_resource_spec.rb +27 -0
- data/spec/unit/lib/instant_api/controller/build_show_spec.rb +24 -0
- data/spec/unit/lib/instant_api/controller/build_update_spec.rb +66 -0
- data/spec/unit/lib/instant_api/controller/builder_spec.rb +18 -0
- data/spec/unit/lib/instant_api/controller/parameters_spec.rb +53 -0
- data/spec/unit/lib/instant_api/model/active_record_query_builder_spec.rb +133 -0
- data/spec/unit/lib/instant_api/model/builder_spec.rb +237 -0
- data/spec/unit/lib/instant_api/model/join_calculator_spec.rb +27 -0
- metadata +202 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
module InstantApi::Controller
|
2
|
+
class BuildDestroy
|
3
|
+
|
4
|
+
def initialize(controller, model_class_name = nil)
|
5
|
+
@controller = controller
|
6
|
+
end
|
7
|
+
|
8
|
+
def build
|
9
|
+
@controller.class_eval(&build_destroy)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def build_destroy
|
15
|
+
Proc.new do
|
16
|
+
def destroy
|
17
|
+
resource.destroy!
|
18
|
+
render status: 200, nothing: true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module InstantApi::Controller
|
2
|
+
class BuildIndex
|
3
|
+
|
4
|
+
attr_reader :model_class_name, :controller
|
5
|
+
|
6
|
+
def initialize(controller, model_class_name)
|
7
|
+
@controller = controller
|
8
|
+
@model_class_name = model_class_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def build
|
12
|
+
controller.class_eval(&build_index)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def build_index
|
17
|
+
body = %Q{
|
18
|
+
require 'instant_api/model/collection'
|
19
|
+
require 'instant_api/controller/parameters'
|
20
|
+
def index
|
21
|
+
parameters = InstantApi::Controller::Parameters.new(params, request.path)
|
22
|
+
collection = InstantApi::Model::Collection.new(#{model_class_name}, parameters)
|
23
|
+
response = {
|
24
|
+
collection: collection.paginated_collection,
|
25
|
+
pagination: {
|
26
|
+
count: collection.count,
|
27
|
+
page: collection.page,
|
28
|
+
per_page: collection.per_page
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
render json: response
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
Proc.new { eval body }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module InstantApi::Controller
|
2
|
+
class BuildNew
|
3
|
+
|
4
|
+
def initialize(controller, model_class_name = nil)
|
5
|
+
@controller = controller
|
6
|
+
end
|
7
|
+
|
8
|
+
def build
|
9
|
+
@controller.class_eval(&build_new)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def build_new
|
15
|
+
Proc.new do
|
16
|
+
def new
|
17
|
+
head :ok
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module InstantApi::Controller
|
2
|
+
class BuildResource
|
3
|
+
def initialize(controller, model_class_name)
|
4
|
+
@controller, @model_class_name = controller, model_class_name
|
5
|
+
end
|
6
|
+
|
7
|
+
def build
|
8
|
+
@controller.class_eval(&build_resource)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def build_resource
|
14
|
+
# TODO: extract this require
|
15
|
+
body = %Q{
|
16
|
+
require 'instant_api/model/resource'
|
17
|
+
require 'instant_api/controller/parameters'
|
18
|
+
def resource
|
19
|
+
@resource ||= begin
|
20
|
+
parameters = InstantApi::Controller::Parameters.new(params, request.path)
|
21
|
+
InstantApi::Model::Resource.new(#{@model_class_name}, parameters).find
|
22
|
+
end
|
23
|
+
end
|
24
|
+
private :resource
|
25
|
+
}
|
26
|
+
Proc.new { eval body }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module InstantApi::Controller
|
2
|
+
class BuildShow
|
3
|
+
|
4
|
+
def initialize(controller, model_class_name = nil)
|
5
|
+
@controller = controller
|
6
|
+
@method = 'show'
|
7
|
+
end
|
8
|
+
|
9
|
+
def build
|
10
|
+
@controller.class_eval(&build_method)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def build_method
|
16
|
+
body = %Q{
|
17
|
+
def #{@method}
|
18
|
+
render json: resource
|
19
|
+
end
|
20
|
+
}
|
21
|
+
|
22
|
+
Proc.new { eval body }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module InstantApi::Controller
|
2
|
+
class BuildUpdate
|
3
|
+
|
4
|
+
attr_reader :model_class_name, :model_name, :controller
|
5
|
+
|
6
|
+
def initialize(controller, model_class_name)
|
7
|
+
@controller = controller
|
8
|
+
@model_class_name = model_class_name
|
9
|
+
@model_name = model_class_name.underscore
|
10
|
+
end
|
11
|
+
|
12
|
+
def build
|
13
|
+
controller.class_eval(&build_update)
|
14
|
+
controller.class_eval(&build_check_strong_parameters)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def build_update
|
20
|
+
Proc.new do
|
21
|
+
def update
|
22
|
+
resource.update_attributes!(check_strong_parameters)
|
23
|
+
raise ActiveRecord::RecordInvalid.new(record) if resource.invalid?
|
24
|
+
render json: resource
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_check_strong_parameters
|
30
|
+
body = if model_class_name.constantize.respond_to?(:strong_parameters)
|
31
|
+
"params.require(:#{model_name}).permit(#{model_class_name}.strong_parameters)"
|
32
|
+
else
|
33
|
+
"params.require(:#{model_name}).permit!"
|
34
|
+
end
|
35
|
+
|
36
|
+
Proc.new do
|
37
|
+
eval %Q{
|
38
|
+
def check_strong_parameters
|
39
|
+
#{body}
|
40
|
+
end
|
41
|
+
private :check_strong_parameters
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rails-api'
|
2
|
+
require 'instant_api/controller/exception_handler'
|
3
|
+
require 'instant_api/controller/build_create'
|
4
|
+
require 'instant_api/controller/build_destroy'
|
5
|
+
require 'instant_api/controller/build_edit'
|
6
|
+
require 'instant_api/controller/build_index'
|
7
|
+
require 'instant_api/controller/build_new'
|
8
|
+
require 'instant_api/controller/build_resource'
|
9
|
+
require 'instant_api/controller/build_update'
|
10
|
+
require 'instant_api/controller/build_show'
|
11
|
+
|
12
|
+
module InstantApi::Controller
|
13
|
+
class Builder
|
14
|
+
|
15
|
+
attr_reader :controller_name, :method_names
|
16
|
+
def initialize(controller_name, method_names)
|
17
|
+
@controller_name = controller_name
|
18
|
+
|
19
|
+
@method_names = method_names.map(&:to_sym)
|
20
|
+
@method_names << :resource if @method_names != [:index]
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_class
|
24
|
+
controller_class_name = "#{controller_name.camelize}Controller"
|
25
|
+
controller = Class.new(ActionController::API)
|
26
|
+
controller.send(:include, InstantApi::Controller::ExceptionHandler)
|
27
|
+
build_methods(controller)
|
28
|
+
|
29
|
+
Object.const_set(controller_class_name, controller)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
CLASSES = {
|
35
|
+
create: InstantApi::Controller::BuildCreate,
|
36
|
+
destroy: InstantApi::Controller::BuildDestroy,
|
37
|
+
edit: InstantApi::Controller::BuildEdit,
|
38
|
+
update: InstantApi::Controller::BuildUpdate,
|
39
|
+
index: InstantApi::Controller::BuildIndex,
|
40
|
+
new: InstantApi::Controller::BuildNew,
|
41
|
+
show: InstantApi::Controller::BuildShow,
|
42
|
+
edit: InstantApi::Controller::BuildEdit,
|
43
|
+
resource: InstantApi::Controller::BuildResource
|
44
|
+
}
|
45
|
+
|
46
|
+
def build_methods(controller)
|
47
|
+
model_class_name = controller_name.camelize.singularize
|
48
|
+
method_names.each do |name|
|
49
|
+
clasz = CLASSES[name]
|
50
|
+
clasz.new(controller, model_class_name).build
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'instant_api'
|
2
|
+
require 'active_record/validations'
|
3
|
+
|
4
|
+
module InstantApi::Controller
|
5
|
+
module ExceptionHandler
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
rescue_from Exception, with: :render_error
|
10
|
+
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
|
11
|
+
rescue_from ActionController::RoutingError, with: :record_not_found
|
12
|
+
rescue_from ActionController::UnknownController, with: :record_not_found
|
13
|
+
rescue_from ActiveRecord::RecordInvalid, with: :rescue_record_invalid
|
14
|
+
end
|
15
|
+
|
16
|
+
def record_not_found(exception)
|
17
|
+
render json: exception_to_json(exception), status: 404
|
18
|
+
end
|
19
|
+
|
20
|
+
def render_error(exception)
|
21
|
+
render json: exception, status: 500
|
22
|
+
end
|
23
|
+
|
24
|
+
def rescue_record_invalid(exception)
|
25
|
+
render json: exception_to_json(exception), status: 422
|
26
|
+
end
|
27
|
+
|
28
|
+
def exception_to_json(exception)
|
29
|
+
hash = case exception
|
30
|
+
when ActiveRecord::RecordNotFound
|
31
|
+
{field: :id, message: exception.message}
|
32
|
+
when ActiveRecord::RecordInvalid
|
33
|
+
exception.record.errors.messages.to_a
|
34
|
+
end
|
35
|
+
{ errors: hash }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module InstantApi::Controller
|
2
|
+
class Parameters
|
3
|
+
INTERNAL_PARAMS = %w(controller action format _method only_path)
|
4
|
+
RAILS_METHODS = %i(new edit)
|
5
|
+
|
6
|
+
attr_reader :params, :request_path
|
7
|
+
|
8
|
+
# params is the rails params {"actionF"=>"index", "controller"=>"countries", "id" => 3}
|
9
|
+
# request: /users/2/addresses/3/edit
|
10
|
+
def initialize(params, request_path)
|
11
|
+
@params = params.except(*INTERNAL_PARAMS)
|
12
|
+
@request_path = request_path
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
params[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
def select(&block)
|
20
|
+
params.select(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
# '/users/2/addresses/3/edit' -> [:users, :addresses]
|
24
|
+
def resources
|
25
|
+
@resources ||= begin
|
26
|
+
resources = request_path.strip.
|
27
|
+
split('/').
|
28
|
+
compact.
|
29
|
+
map(&:strip).
|
30
|
+
each_with_index.
|
31
|
+
select { |_, index| index % 2 == 1 }.
|
32
|
+
map { |a, _| a.to_sym }
|
33
|
+
|
34
|
+
*rest, tail = *resources
|
35
|
+
if RAILS_METHODS.index(tail)
|
36
|
+
rest
|
37
|
+
else
|
38
|
+
resources
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'action_dispatch/routing/inspector'
|
2
|
+
require 'instant_api/controller/builder'
|
3
|
+
|
4
|
+
module InstantApi::Controller
|
5
|
+
class Routes
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
Rails.application.reload_routes!
|
9
|
+
@routes = Rails.application.routes.routes.map do |route|
|
10
|
+
ActionDispatch::Routing::RouteWrapper.new(route)
|
11
|
+
end.reject(&:internal?)
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_controllers
|
15
|
+
controllers_by_routes = Hash.new
|
16
|
+
@routes.each do |route|
|
17
|
+
controller = route.defaults[:controller]
|
18
|
+
list = controllers_by_routes[controller] || []
|
19
|
+
controllers_by_routes[controller] = list << route
|
20
|
+
end
|
21
|
+
|
22
|
+
controllers = controllers_by_routes.map do |controller, routes|
|
23
|
+
methods = routes.map { |route| route.defaults[:action] }
|
24
|
+
[controller, methods]
|
25
|
+
end
|
26
|
+
|
27
|
+
controllers.each do |controller, methods|
|
28
|
+
InstantApi::Controller::Builder.new(controller, methods).build_class
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
=begin
|
37
|
+
routes.each do |route|
|
38
|
+
puts [ route.name,
|
39
|
+
route.verb,
|
40
|
+
route.path,
|
41
|
+
route.reqs,
|
42
|
+
route.defaults[:action],
|
43
|
+
route.defaults[:controller],
|
44
|
+
route.json_regexp].join(' - ')
|
45
|
+
end;nil
|
46
|
+
=end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'instant_api/model/association_reflector'
|
2
|
+
|
3
|
+
module InstantApi::Model
|
4
|
+
class ActiveRecordQueryBuilder
|
5
|
+
attr_reader :model
|
6
|
+
def initialize(model)
|
7
|
+
@model = model
|
8
|
+
end
|
9
|
+
|
10
|
+
def query(params)
|
11
|
+
if has_associations?(params)
|
12
|
+
reflector = InstantApi::Model::AssociationReflector.new(params.resources)
|
13
|
+
model.joins(reflector.calculate_join).
|
14
|
+
where(reflector.calculate_conditions(params))
|
15
|
+
else
|
16
|
+
model.all
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_first(params)
|
21
|
+
result = if has_associations?(params)
|
22
|
+
query(params).first
|
23
|
+
else
|
24
|
+
model.find(params[:id])
|
25
|
+
end
|
26
|
+
raise ActiveRecord::RecordNotFound.new if !result
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def has_associations?(params)
|
33
|
+
params.resources.size > 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
|
2
|
+
#params.resources: [:users, :addresses]
|
3
|
+
#request path: /users/1/addresses
|
4
|
+
# query: Address.joins(:users)
|
5
|
+
|
6
|
+
# has_many
|
7
|
+
# has_one
|
8
|
+
# belongs_to
|
9
|
+
# has_and_belongs_to_many
|
10
|
+
# Company
|
11
|
+
# has_many :employees
|
12
|
+
# company.employees PLURAL
|
13
|
+
# Employee
|
14
|
+
# belongs_to :company
|
15
|
+
# employee.company SINGULAR
|
16
|
+
# has_one :office
|
17
|
+
# company.office
|
18
|
+
# has_and_belongs_to_many
|
19
|
+
# company.offices
|
20
|
+
|
21
|
+
|
22
|
+
module InstantApi::Model
|
23
|
+
class AssociationReflector
|
24
|
+
|
25
|
+
def initialize(association_list)
|
26
|
+
@association_list = association_list
|
27
|
+
end
|
28
|
+
|
29
|
+
def calculate_join
|
30
|
+
*associations, resource = *@association_list
|
31
|
+
klass = to_class(resource)
|
32
|
+
first, *rest = *associations.reverse
|
33
|
+
|
34
|
+
result = []
|
35
|
+
if (assoc = association(klass, first))
|
36
|
+
result << assoc.name.to_sym
|
37
|
+
klass = to_class(first)
|
38
|
+
end
|
39
|
+
|
40
|
+
if rest
|
41
|
+
rest.each do |association_name|
|
42
|
+
if (assoc = association(klass, association_name))
|
43
|
+
result << {klass.name.downcase.to_sym => assoc.name.to_sym}
|
44
|
+
klass = to_class(association_name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
def calculate_conditions(params)
|
53
|
+
result = Hash.new
|
54
|
+
result[:id] = params[:id] if params[:id]
|
55
|
+
|
56
|
+
resource, *rest = *params.resources
|
57
|
+
klass = to_class(resource)
|
58
|
+
rest.map do |association_name|
|
59
|
+
if (assoc = association(klass, association_name))
|
60
|
+
table = join_table(assoc)
|
61
|
+
foreign_key = foreign_key(assoc)
|
62
|
+
result[table] = { foreign_key => params[foreign_key] }
|
63
|
+
end
|
64
|
+
|
65
|
+
resource = association_name
|
66
|
+
klass = to_class(resource)
|
67
|
+
end
|
68
|
+
|
69
|
+
result
|
70
|
+
end
|
71
|
+
|
72
|
+
def join_table(assoc)
|
73
|
+
if assoc.has_and_belongs_to_many?
|
74
|
+
assoc.join_table.to_sym
|
75
|
+
else
|
76
|
+
assoc.name.to_sym
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def foreign_key(assoc)
|
81
|
+
assoc.foreign_key.to_sym
|
82
|
+
end
|
83
|
+
|
84
|
+
def association(klass, name)
|
85
|
+
klass.reflect_on_association(name.to_s.singularize.to_sym) ||
|
86
|
+
klass.reflect_on_association(name.to_s.pluralize.to_sym)
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_class(symbol)
|
90
|
+
symbol.to_s.classify.constantize
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|