module JsonapiForRails::Controller::Actions::Object::InstanceMethods

Public Instance Methods

create() click to toggle source

implements Create and Update operations

# File lib/jsonapi_for_rails/controller/actions/object.rb, line 34
def create

        # attributes
        begin
                attrs = jsonapi_received_attributes
                if attrs
                        if @jsonapi_record
                                # update
                                @jsonapi_record.update! attrs
                        else
                                # create
                                @jsonapi_record = jsonapi_model_class.new attrs
                                @jsonapi_record.save!
                        end
                end
        rescue NameError => e
                jsonapi_render_errors 500, "Model class not found."
                return
        rescue 
                jsonapi_render_errors 500, @jsonapi_record.to_jsonapi_errors_hash
                return
        end

        # relationships
        jsonapi_received_relationships.each do |relationship|
                begin
                                # to-one
                                if relationship[:definition][:type] == :to_one
                                        @jsonapi_record.send :"#{relationship[:definition][:name]}=", relationship[:params][:data]
                                        next
                                end

                                # to-many
                                @jsonapi_record.send(relationship[:definition][:name]).send :clear # initialize the relation
                                
                                relationship[:params][:data].each do |item|
                                        object = relationship[:receiver][:class].find_by_id item[:id]
                                        @jsonapi_record.send(relationship[:definition][:name]).send :<<, object
                                end

                rescue 
                        # Should not happen
                        jsonapi_render_errors 500, "Relationship could not be created."
                        return
                end
        end

        show
end
destroy() click to toggle source
# File lib/jsonapi_for_rails/controller/actions/object.rb, line 159
def destroy
        jsonapi_render_errors 500, "Not implemented."
end
index() click to toggle source

TODO: pagination

# File lib/jsonapi_for_rails/controller/actions/object.rb, line 12
def index
        @json = {data: []}
        jsonapi_model_class.all.each do |record|
                @json[:data] << {
                        type: record.class.to_s.underscore.pluralize, # TODO: factor out type generation from class
                        id:   record.id.to_s
                }
        end

        # Links
        if @jsonapi_links
                @json[:links] = {
                        self: self.send(
                                "#{jsonapi_model_type}_path" # TODO: factor out
                        )
                }
        end

        jsonapi_render @json
end
jsonapi_received_attributes() click to toggle source

Extracts record attributes from received params. Use this for creating/updating a database record. Note that relationships (has_one associations etc) are filtered out but are still available in the original params.

# File lib/jsonapi_for_rails/controller/actions/object.rb, line 169
def jsonapi_received_attributes
        begin
                params.require(
                        :data
                ).require(
                        :attributes
                ).permit(
                        *jsonapi_model_class.attribute_names
                ).reject do |key, value|
                        # ignore automatically generated attributes
                        %w(
                                id 
                                created_at created_on 
                                updated_at updated_on
                        ).include?(
                                key.to_s
                        ) or 

                        # ignore reference attributes
                        key.to_s =~ /_id$/
                end
        rescue  ActionController::ParameterMissing => e
                nil
        end
end
jsonapi_received_relationships() click to toggle source

TODO: define a separate method for relationship actions (i.e. when params != nil)

# File lib/jsonapi_for_rails/controller/actions/object.rb, line 224
def jsonapi_received_relationships
        # Relationship definitions for current model
        rels = jsonapi_relationships

        # Consider only current relationship for relationship actions
        # (params[:relationship] contains the relationship name)
        if params[:relationship] 

                rels.select! do |rel|
                        rel[:name].to_sym == params[:relationship].to_sym
                end

                # If no relationship is received, then return the definition only
                if request.method == "GET"
                        return rels.collect do |rel|
                                {definition: rel}
                        end
                end

        end

        rels.collect do |relationship|
                begin
                        received_params = nil

                        # Relationship action
                        if params[:relationship]
                                received_params =  params.permit({
                                        data: [
                                                :type, :id
                                        ]
                                })

                        # Object action
                        else
                                received_params =  params.require( 
                                        :data
                                ).require(
                                        :relationships
                                ).require(
                                        relationship[:name]
                                ).permit({
                                        data: [
                                                :type, :id
                                        ]
                                })
                        end
                        # => {"data"=>{"type"=>"users", "id"=>1}}                                         # sample value for a to-one association
                        # => {"data"=>[{"type"=>"properties", "id"=>1}, {"type"=>"properties", "id"=>2}]} # sample value for a to-many association

                        # is received data conformant to the database schema?
                        conformant = true
                        loop do
                                # to-many
                                if received_params[:data].kind_of? Array
                                        if relationship[:type] != :to_many
                                                conformant = false
                                                break
                                        end
                                        received_params[:data].each do |item|
                                                next if item[:type].to_sym == relationship[:receiver][:type]
                                                conformant = false
                                                break
                                        end
                                        break
                                end

                                # to-one
                                if relationship[:type] != :to_one
                                        conformant = false
                                        break
                                end
                                conformant = false unless received_params[:data][:type].to_sym == relationship[:receiver][:type]

                                break
                        end
                        next unless conformant

                        {
                                definition: relationship,
                                params:     received_params
                        }
                rescue ActionController::ParameterMissing => e

                        # nil assignment to to-one relationship?
                        if relationship[:type] == :to_one
                                begin
                                        if params[:relationship] # relationship action
                                                received_params =  params.permit(
                                                        :data
                                                )
                                        else
                                                received_params =  params.require( 
                                                        :data
                                                ).require(
                                                        :relationships
                                                ).require(
                                                        relationship[:name]
                                                ).permit(
                                                        :data
                                                )
                                        end

                                        # received nil?
                                        next if received_params[:data] # TODO: should return error to client?

                                        next {
                                                definition: relationship,
                                                params:     received_params
                                        }
                                rescue ActionController::ParameterMissing => e
                                end
                        end

                        nil
                end
        end.compact
end
jsonapi_relationships() click to toggle source

Definitions of all relationships for current model

# File lib/jsonapi_for_rails/controller/actions/object.rb, line 196
def jsonapi_relationships
        jsonapi_model_class.reflect_on_all_associations.collect do |association|
                #type = nil

                type = :to_one if [
                        ActiveRecord::Reflection::HasOneReflection, 
                        ActiveRecord::Reflection::BelongsToReflection
                ].include? association.class

                type = :to_many if [
                        ActiveRecord::Reflection::HasManyReflection, 
                        ActiveRecord::Reflection::HasAndBelongsToManyReflection
                ].include? association.class

                next unless type

                {
                        name: association.name,
                        type: type,
                        receiver: {
                                type:  association.klass.to_s.underscore.pluralize.to_sym,
                                class: association.klass.to_s.constantize
                        }
                }
        end.compact
end
show() click to toggle source
# File lib/jsonapi_for_rails/controller/actions/object.rb, line 84
def show
        # Attributes and relationships
        @json = @jsonapi_record.to_jsonapi_hash(
                 sparse_fieldset: @jsonapi_sparse_fieldsets[jsonapi_model_type]
        )

        # Links
        if @jsonapi_links

                # Current resource
                @json[:data][:links] = {
                        self: self.send(
                                "#{jsonapi_model_type.to_s.singularize}_path", # TODO: factor out
                                @jsonapi_record.id
                        )
                }

                # Related resources
                @json[:data][:relationships].each do |rel_name, rel|
                        rel[:links] = {
                                self: "#{@json[:data][:links][:self]}/relationships/#{rel_name}"
                        }
                end
        end

        #$stderr.puts "#{@json}"

        # Include resources
        # TODO: relationship paths when including resources (http://jsonapi.org/format/1.0/#fetching-includes)
        if @jsonapi_include and @json[:data][:relationships]
                @json[:include] = []
                @jsonapi_include.each do |rel_name|
                        rel = @json[:data][:relationships][rel_name]
                        next unless rel
                        rel = rel[:data]
                        next unless rel
                        rel = [rel] if rel.kind_of?(Hash)
                        rel.each do |r|
                                type = r[:type].to_sym
                                klass = nil
                                begin
                                        klass = r[:type].singularize.camelize.constantize
                                rescue NameError => e
                                        next                                                                   
                                end
                                r = klass.find_by_id r[:id]
                                next unless r

                                # Attributes and relationships
                                r = r.to_jsonapi_hash(
                                        sparse_fieldset: @jsonapi_sparse_fieldsets[type]
                                )

                                # Links
                                if @jsonapi_links
                                        r[:links] = {
                                                self: self.send(
                                                        "#{r[:data][:type].to_s.singularize}_path", # TODO: factor out
                                                        r[:data][:id]
                                                )
                                        }
                                end

                                @json[:include] << r
                        end
                end
        end

        jsonapi_render @json
end
update() click to toggle source
# File lib/jsonapi_for_rails/controller/actions/object.rb, line 155
def update
        create
end