<NoMethodError: undefined метод `read_attribute_for_serialization 'для # <Record:: ActiveRecord_Relation:

Я получаю сообщение об ошибке:

<NoMethodError: undefined method `read_attribute_for_serialization' for #<Record::ActiveRecord_Relation:0x007faa7cfe3318>>

Ошибка в третьей строке фрагмента.

  def artist
    @records = Record.where('artist_id = ' + params[:artist_id])
    render :json => @records, serializer: RecordSummarySerializer
  end

Это альтернативный сериализатор для контроллера RecordsContrller. Другой, "RecordsSerializer", отлично работает.

Поиск по этой ошибке вызвал несколько решений. Некоторым было неясно, куда добавить код. Другой предложил добавить:

alias :read_attribute_for_serialization :send

в класс, где происходит ошибка. Это не сработало для меня. Я также просмотрел документацию о драгоценных камнях. Я нашел пример использования сериализатора:. Было ясно, что нужен другой код.

Я использую Ruby 2.3.0 и Rails 5.0.0.

контроллер

class RecordsController < ApplicationController
...
  def index
    @records = Record.order('title')
    render :json => @records
  end

  def artist
    @records = Record.where('artist_id = ' + params[:artist_id])
    render :json => @records, serializer: RecordSummarySerializer
  end
...
end

Model

class Record < ActiveRecord::Base
  belongs_to :artist
  belongs_to :label
  belongs_to :style
  has_many :tracks
  has_many :credits

  validates :title, presence: true
  validates :catalog, presence: true
end

record_summary_serializer.rb

include ActiveModel::Serialization
class RecordSummarySerializer < ActiveModel::Serializer
  attributes :id, :artist_id, :label_id, :style_id, :title, :catalog,
             :recording_date, :penguin, :category
end

record_serializer.rb

class RecordSerializer < ActiveModel::Serializer
  attributes :id, :artist_id, :label_id, :style_id, :title, :catalog,     :alternate_catalog,
         :recording_date, :notes, :penguin, :category
  has_one :artist
  has_many :tracks
end

Схема записей

  create_table "records", unsigned: true, force: :cascade, options:   "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
    t.string   "title",             limit: 50
    t.string   "catalog",           limit: 20,                          null: false
    t.string   "alternate_catalog", limit: 20
    t.integer  "artist_id",                                                          unsigned: true
    t.integer  "label_id",                                                null: false, unsigned: true
    t.integer  "style_id",                                                           unsigned: true
    t.datetime "recording_date"
    t.text     "notes",             limit: 4294967295
    t.string   "penguin",           limit: 50
    t.string   "category",          limit: 50,         default: "jazz"
    t.index ["artist_id"], name: "RecordHasOneArtist", using: :btree
    t.index ["label_id"], name: "RecordHasOneLabel", using: :btree
    t.index ["style_id"], name: "RecordHasOneStyle", using: :btree
  end

Я только заметил, первичный ключ, id, не отображается в схеме. Я вижу это в Sequel Pro, когда просматриваю структуру таблицы.

Update

Я добавил код, предложенный @JMazzy. Теперь я получаю сообщение об ошибке:

<NoMethodError: undefined method `id' for #<Record::ActiveRecord_Relation:0x007faa8005a9d8>\nDid you mean?  ids>

Ответ 1

У меня была такая же ошибка и я обнаружил, что изменение serializer: на each_serializer: в контроллере решило проблему.

контроллер

class RecordsController < ApplicationController
...
  def artist
    @records = Record.where('artist_id = ' + params[:artist_id])
    render :json => @records, each_serializer: RecordSummarySerializer
  end
...
end

record_summary_serializer.rb - можно удалить строку include

class RecordSummarySerializer < ActiveModel::Serializer
  attributes :id, :artist_id, :label_id, :style_id, :title, :catalog,
             :recording_date, :penguin, :category
end

От active_model_serializers документация.

Обновлена ​​ссылка. спасибо Lowryder

Ответ 2

Вам нужно добавить include ActiveModel::Serialization к вашей модели. Расширенная сериализация не включена по умолчанию в ActiveModel. См. этот ответ на GitHub.

Ответ 3

Я исправил свою ближайшую проблему, изменив собственный сериализатор на RecordDetailSerializer и вызвав его из моего метода show в контроллере. Когда я удалил include @JMazzy, предположил, что он все еще работает. Есть еще что-то вялое. Если я использую собственный метод в методе индекса:

def index
  @records = Record.order('title')
  render :json => @records, serializer: RecordDetailSerializer
end

Я получаю ошибку на недостающем id, показанном внизу моего вопроса выше. Однако, когда я использую его в своем методе show:

def show
  @record = Record.find(params[:id])
  render :json => @record, serializer: RecordDetailSerializer
end

Если я удалю поле проблемы, следующее поле в списке станет проблемой. Это не проблема для меня, поскольку я всегда могу ограничить собственные сериализаторы и отдельные элементы.

Ответ 4

<NoMethodError: undefined method `read_attribute_for_serialization'

Эта ошибка может произойти, когда сериализуемый объект nil. Рассмотрите распечатку отладки объекта, который вы сериализуете, чтобы проверить, есть ли он nil:

def show
  product = Product.find_by(id: params[:id])
  p "Is product nil? #{product.nil?}"
  render json: product
end

Если объект (product в вышеприведенном фрагменте) равен nil, вы можете увидеть сообщение NoMethodError, указанное выше, из-за вызова nil.read_attribute_for_serialization.