Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Active Model Serializers - undefined method for route helpers

I am building a new application with the rails-api gem. I am using active_model_serializers to customize my JSON responses. In trying to add a url attribute to serializer, I get an error indicating that my resource's route helper methods are undefined. Pertinent code to follow:

# Routes
Rails.application.routes.draw do
  namespace :api, defaults: { format: 'json' } do
    namespace :v1 do
      resources :tasks, except: [:new, :edit]
    end
  end
end

# Controller - api/v1/tasks_controller.rb
class Api::V1::TasksController < ApplicationController
  before_action :set_task, only: [:show, :update, :destroy]

  # GET /tasks
  # GET /tasks.json
  def index
    @tasks = Task.all

    render json: @tasks
  end

  # GET /tasks/1
  # GET /tasks/1.json
  def show
    render json: @task
  end

  # POST /tasks
  # POST /tasks.json
  def create
    @task = Task.new(task_params)

    if @task.save
      render json: @task, status: :created, location: api_v1_task_path(@task.id)
    else
      render json: @task.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /tasks/1
  # PATCH/PUT /tasks/1.json
  def update
    @task = Task.find(params[:id])

    if @task.update(task_params)
      head :no_content
    else
      render json: @task.errors, status: :unprocessable_entity
    end
  end

  # DELETE /tasks/1
  # DELETE /tasks/1.json
  def destroy
    @task.destroy

    head :no_content
  end

  private

    def set_task
      @task = Task.find(params[:id])
    end

    def task_params
      params.require(:task).permit(:name)
    end
end

# Serializer
class TaskSerializer < ActiveModel::Serializer
  attributes :id, :name, :url

  def url
    api_v1_task_url(object)
  end
end

As you can see, I am using namespaced routes and have the controllers working. I receive an undefined method 'api_v1_task_url error when I try and retrieve a task. I can't figure out why the helper methods aren't included. I'm baffled because every tutorial I find on adding custom attributes like this don't make any adjustments for using these gems (rails-api and active_model_serializers).

Here is some more relevant information: rails version: 4.2.6 rails-api version: 0.4.0 active_model_serializers version: 0.10.0.rc5

Edit: Here is the output of rake routes

     Prefix Verb    URI Pattern                 Controller#Action
api_v1_tasks GET    /api/v1/tasks(.:format)     api/v1/tasks#index {:format=>"json"}
             POST   /api/v1/tasks(.:format)     api/v1/tasks#create {:format=>"json"}
 api_v1_task GET    /api/v1/tasks/:id(.:format) api/v1/tasks#show {:format=>"json"}
             PATCH  /api/v1/tasks/:id(.:format) api/v1/tasks#update {:format=>"json"}
             PUT    /api/v1/tasks/:id(.:format) api/v1/tasks#update {:format=>"json"}
             DELETE /api/v1/tasks/:id(.:format) api/v1/tasks#destroy {:format=>"json"}

Edit 2: Following the suggestion below, I tried:

# Serializer
class TaskSerializer < ActiveModel::Serializer
  attributes :id, :name, :url

  def url
    link(:self) { api_v1_task_url(object) }
  end
end

And received a undefined method 'link' error.

Edit 3: @beauby did point out I was using this method in the incorrect place, however using it correctly still does not create an attribute via a serializer method as I've seen work in numerous tutorials such as this one: http://railscasts.com/episodes/409-active-model-serializers?view=asciicast. It creates a links property following the JSONAPI schema, which while helpful and something I will remember, is not what I am trying to accomplish.

like image 792
Kyle Shevlin Avatar asked Feb 27 '26 05:02

Kyle Shevlin


2 Answers

You can add Rails.application.routes.url_helpers to your TaskSerializer to use url_helpers.

  class TaskSerializer < ActiveModel::Serializer
    include Rails.application.routes.url_helpers

    attributes :name

    link(:self) { api_v1_task_url(object) }
  end

You can also use :json as your ActiveModel Adapter and manually add resource location.

  class TaskSerializer < ActiveModel::Serializer
    include Rails.application.routes.url_helpers

    attributes :name, :resource_location

    def resource_location 
      api_v1_task_url(object)
    end
  end
like image 135
Aschen Avatar answered Mar 02 '26 16:03

Aschen


If you are using the JsonApi adapter, then you cannot use the url_helpers from inside an attribute definition but you can use it from inside a link definition, as follows:

  class TaskSerializer < ActiveModel::Serializer
    attributes :name
    link(:self) { api_v1_task_url(object) }
  end
like image 41
beauby Avatar answered Mar 02 '26 16:03

beauby