Module: Heimdallr::LegacyResource Deprecated

Extended by:
ActiveSupport::Concern
Defined in:
lib/heimdallr/legacy_resource.rb

Overview

Deprecated.

Will be removed ASAP. Please don’t use it in favour of github.com/roundlake/heimdallr-resource/

Heimdallr LegacyResource is a boilerplate for simple creation of REST endpoints, most of which are quite similar and thus may share a lot of code.

The minimal controller possible would be:

class MiceController < ApplicationController
  include Heimdallr::Resource

  # Class Mouse must include Heimdallr::Model.
  resource_for :mouse
end

Resource is built with Convention over Configuration principle in mind; that is, instead of providing complex configuration syntax, Resource consists of a lot of small, easy to override methods. If some kind of default behavior is undesirable, then one can just override the relative method in the particular controller or, say, define a module if the changes are to be shared between several controllers. You are encouraged to explore the source of this class.

Resource allows to perform efficient operations on collections of objects. The #create, #update and #destroy actions accept both a single object/ID or an array of objects/IDs. The cardinal _modus

Resource expects a method named security_context to be defined either in the controller itself or, more conveniently, in any of its ancestors, likely ApplicationController. This method can often be aliased to current_user.

Resource only works with ActiveRecord.

See also Resource::ClassMethods.

Defined Under Namespace

Modules: ClassMethods

Actions collapse

Configuration collapse

Instance Method Details

#createObject

POST /resources

This action creates one or more records from the passed parameters. It can accept both arrays of attribute hashes and single attribute hashes.

After the creation, it calls #render_data.

See also #load_referenced_resources and #with_objects_from_params.



72
73
74
75
76
77
78
# File 'lib/heimdallr/legacy_resource.rb', line 72

def create
  with_objects_from_params(replace: true) do |object, attributes|
    restricted_model.create(attributes)
  end

  render_data verify: true
end

#destroyObject

DELETE /resources/1,2

This action destroys one or more records. It expects resource IDs to be passed comma-separated in params[:id].

See also #load_referenced_resources.



114
115
116
117
118
119
120
# File 'lib/heimdallr/legacy_resource.rb', line 114

def destroy
  with_objects_from_params do |object, attributes|
    object.destroy
  end

  render :json => {}, :status => :ok
end

#editObject

GET /resources/1/edit

This action renders a JSON representation of fields whitelisted for updating. See also #new.



84
85
86
87
88
# File 'lib/heimdallr/legacy_resource.rb', line 84

def edit
  render :json => {
    :fields => model.restrictions(security_context).allowed_fields[:update]
  }
end

#indexObject

GET /resources

This action does nothing by itself, but it has a load_all_resources filter attached.



40
41
42
# File 'lib/heimdallr/legacy_resource.rb', line 40

def index
  render_data
end

#load_all_resourcesObject (protected)

Loads all resources in the current scope to @resources.

Is automatically applied to #index.



175
176
177
178
# File 'lib/heimdallr/legacy_resource.rb', line 175

def load_all_resources
  @multiple_resources = true
  @resources = restricted_model
end

#load_referenced_resourcesObject (protected)

Loads several resources from the current scope, referenced by params[:id] with a comma-separated string like “1,2,3”, to @resources.

Is automatically applied to #show, #update and #destroy.



184
185
186
187
188
189
190
191
192
# File 'lib/heimdallr/legacy_resource.rb', line 184

def load_referenced_resources
  if params[:id][0] == '*'
    @multiple_resources = true
    @resources = restricted_model.find(params[:id][1..-1].split(','))
  else
    @multiple_resources = false
    @resource  = restricted_model.find(params[:id])
  end
end

#modelClass (protected)

Return the associated model class.

Returns:

  • (Class)

    associated model



128
129
130
# File 'lib/heimdallr/legacy_resource.rb', line 128

def model
  self.class.model
end

#newObject

GET /resources/new

This action renders a JSON representation of fields whitelisted for creation. It does not include any fixtures or validations.

Examples:

{ 'fields': [ 'topic', 'content' ] }


58
59
60
61
62
# File 'lib/heimdallr/legacy_resource.rb', line 58

def new
  render :json => {
    :fields => model.restrictions(security_context).allowed_fields[:create]
  }
end

#render_data(options = {}) ⇒ Object (protected)

Render a modified collection in #create, #update and similar actions.



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/heimdallr/legacy_resource.rb', line 195

def render_data(options={})
  if @multiple_resources
    if options[:verify] && @resources.any?(&:invalid?)
      render :json => { errors: @resources.map(&:errors) }, :status => :unprocessable_entity
    else
      render :action => :index
    end
  else
    if options[:verify] && @resource.invalid?
      render :json => @resource.errors, :status => :unprocessable_entity
    else
      render :action => :show
    end
  end
end

#restricted_modelObject (protected)

Return the scoped and restricted model. By default this method restricts the result of #scoped_model with security_context, which is expected to be defined on this class or its ancestors.



168
169
170
# File 'lib/heimdallr/legacy_resource.rb', line 168

def restricted_model
  scoped_model.restrict(security_context, implicit: true)
end

#scoped_modelObject (protected)

Return the appropriately scoped model. By default this method delegates to self.model.scoped; you may override it for nested resources so that it would only return the nested set.

For example, this code would not allow user to perform any actions with a transaction from a wrong account, raising RecordNotFound instead:

# transactions_controller.rb
class TransactionsController < ApplicationController
  include Heimdallr::Resource

  resource_for :transactions

  protected

  def scoped_model
    Account.find(params[:account_id]).transactions
  end
end

# routes.rb
Foo::Application.routes.draw do
  resources :accounts do
    resources :transactions
  end
end

Returns:

  • ActiveRecord scope



161
162
163
# File 'lib/heimdallr/legacy_resource.rb', line 161

def scoped_model
  self.model.scoped
end

#showObject

GET /resource/1

This action does nothing by itself, but it has a load_one_resource filter attached.



47
48
49
# File 'lib/heimdallr/legacy_resource.rb', line 47

def show
  render_data
end

#updateObject

PUT /resources/1,2

This action updates one or more records from the passed parameters. It expects resource IDs to be passed comma-separated in params[:id], and expects them to be in the order corresponding to the order of actual attribute hashes.

After the updating, it calls #render_data.

See also #load_referenced_resources and #with_objects_from_params.



100
101
102
103
104
105
106
# File 'lib/heimdallr/legacy_resource.rb', line 100

def update
  with_objects_from_params do |object, attributes|
    object.update_attributes attributes
  end

  render_data verify: true
end

#with_objects_from_params(options = {}) {|attributes, index| ... } ⇒ Object (protected)

Fetch one or several objects passed in params and yield them to a block, wrapping everything in a transaction.

Yields:

Yield Parameters:

  • attributes (Hash)
  • index (Integer)


217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/heimdallr/legacy_resource.rb', line 217

def with_objects_from_params(options={})
  model.transaction do
    if @multiple_resources
      begin
        name = model.name.underscore.pluralize
        if params[name].is_a? Hash
          enumerator = params[name].keys.each
        else
          enumerator = params[name].each_index
        end

        result = enumerator.map do |index|
          yield(@resources[index.to_i], params[name][index])
        end
      ensure
        @resources = result if options[:replace]
      end
    else
      begin
        result = yield(@resource, params[model.name.underscore])
      ensure
        @resource  = result if options[:replace]
      end
    end
  end
end