Class: Rack::Scaffold

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/scaffold.rb,
lib/rack/scaffold/adapters.rb

Defined Under Namespace

Modules: Adapters

Constant Summary collapse

ACTIONS =
[:create, :read, :update, :destroy]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Scaffold

Returns a new instance of Scaffold.

Raises:

  • (ArgumentError)


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/rack/scaffold.rb', line 12

def initialize(options = {})
  raise ArgumentError, "Missing option: :model or :models" unless options[:model] or options[:models]

  if options[:models] and options[:models].kind_of?(Array)
    @app = Rack::Cascade.new(options.delete(:models).collect{|model| self.class.new(options.dup.merge({model: model}))}) and return
  end

  @app = Class.new(Sinatra::Base) do
    use Rack::PostBodyContentTypeParser
    helpers Sinatra::Param

    before do
      content_type :json
    end

    disable :raise_errors, :show_exceptions

    def last_modified_time(resource, resources)
      update_timestamp_field = resource.update_timestamp_field.to_sym
      most_recently_updated = resources.class.include?(Enumerable) ? resources.max_by(&update_timestamp_field) : resources

      timestamp = request.env['HTTP_IF_MODIFIED_SINCE']
      timestamp = most_recently_updated.send(update_timestamp_field) if most_recently_updated
      timestamp
    end
  end

  @actions = (options[:only] || ACTIONS) - (options[:except] || [])

  @adapter = Rack::Scaffold.adapters.detect{|adapter| adapter === options[:model]}
  raise "No suitable adapters found for #{options[:model]} in #{Rack::Scaffold.adapters}" unless @adapter

  resources = Array(@adapter.resources(options[:model], options))
  resources.each do |resource|
    @app.instance_eval do
      post "/#{resource.plural}/?" do
        if record = resource.create!(params)
          status 201
          {"#{resource.singular}" => record}.to_json
        else
          status 406
          {errors: record.errors}.to_json
        end
      end
    end if @actions.include?(:create)

    @app.instance_eval do
      get "/#{resource.plural}/?" do
        if params[:page] or params[:per_page]
          param :page, Integer, default: 1, min: 1
          param :per_page, Integer, default: 100, in: (1..100)

          resources = resource.paginate(params[:per_page], (params[:page] - 1) * params[:per_page])
          last_modified(last_modified_time(resource, resources)) if resource.timestamps?

          {
            "#{resource.plural}" => resources,
            page: params[:page],
            total: resource.count
          }.to_json
        else
          param :limit, Integer, default: 100, in: (1..100)
          param :offset, Integer, default: 0, min: 0

          resources = resource.paginate(params[:limit], params[:offset])
          last_modified(last_modified_time(resource, resources)) if resource.timestamps?

          {
            "#{resource.plural}" => resources
          }.to_json
        end
      end

      get "/#{resource.plural}/:id/?" do
        record = resource[params[:id]] or halt 404
        last_modified(last_modified_time(resource, record)) if resource.timestamps?
        {"#{resource.singular}" => record}.to_json
      end

    end if @actions.include?(:read)

    @app.instance_eval do
      put "/#{resource.plural}/:id/?" do
        record = resource[params[:id]] or halt 404
        if record.update!(params)
          status 200
          {"#{resource.singular}" => record}.to_json
        else
          status 406
          {errors: record.errors}.to_json
        end
      end
    end if @actions.include?(:update)

    @app.instance_eval do
      delete "/#{resource.plural}/:id/?" do
        record = resource[params[:id]] or halt 404
        if record.destroy
          status 200
        else
          status 406
          {errors: record.errors}.to_json
        end
      end
    end if @actions.include?(:destroy)

    # @app.instance_eval do
    #   entity.relationships.each do |relationship|
    #     next unless relationship.to_many?

    #     get "/#{resource.plural}/:id/#{relationship.name}/?" do
    #       {relationship.name => resource[params[:id]].send(relationship.name)}.to_json
    #     end
    #   end
    # end
  end
end

Class Method Details

.adaptersObject



3
4
5
# File 'lib/rack/scaffold/adapters.rb', line 3

def self.adapters
  @@adapters ||= []
end

Instance Method Details

#call(env) ⇒ Object



130
131
132
# File 'lib/rack/scaffold.rb', line 130

def call(env)
  @app.call(env)
end