Reputation: 4592
I'm getting the error:
<NoMethodError: undefined method `read_attribute_for_serialization' for #<Record::ActiveRecord_Relation:0x007faa7cfe3318>>
The error is on third line of the snippet.
def artist
@records = Record.where('artist_id = ' + params[:artist_id])
render :json => @records, serializer: RecordSummarySerializer
end
This is an alternate serializer for the controller RecordsContrller. The other one, 'RecordsSerializer, works fine.
A search on this error brought up a few solutions. Some were unclear as to where one would add code. Another suggested adding:
alias :read_attribute_for_serialization :send
to the class where the error occurs. It didn't work for me. I also looked through the gem documentation. I found an example of the use of serializer:. It was clear any other code was needed.
I'm using Ruby 2.3.0 and 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
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
include ActiveModel::Serialization
class RecordSummarySerializer < ActiveModel::Serializer
attributes :id, :artist_id, :label_id, :style_id, :title, :catalog,
:recording_date, :penguin, :category
end
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
I just noticed, the primary key, id, doesn't appear in the schema. I see it in Sequel Pro when I view the table structure.
I added the the code suggested by @JMazzy. I now get the error:
<NoMethodError: undefined method `id' for #<Record::ActiveRecord_Relation:0x007faa8005a9d8>\nDid you mean? ids>
Upvotes: 33
Views: 41873
Reputation: 27603
I got this error when trying to serialize an array of records in a view template.
I had:
InviteSerializer.new(@invites) } # throws errror
I needed:
@invites.map { |i| InviteSerializer.new(i) } # works!
Upvotes: 0
Reputation: 518
Adding serializable_hash
and directly initializing the constructor, i.e.
def artist
@records = Record.where('artist_id', params[:artist_id])
render json: RecordSummarySerializer.new(@records).serializable_hash
end
...solved it for me.
Upvotes: 1
Reputation: 646
I had the same error and found changing serializer:
to each_serializer:
in the controller solved the issue.
Controller
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 - can remove the include line
class RecordSummarySerializer < ActiveModel::Serializer
attributes :id, :artist_id, :label_id, :style_id, :title, :catalog,
:recording_date, :penguin, :category
end
From active_model_serializers documentation.
Updated link. thanks Lowryder
Upvotes: 52
Reputation: 10073
<NoMethodError: undefined method `read_attribute_for_serialization'
This error can happen when the object being serialized is nil
. Consider print debugging the object you are serializing to check if it is nil
:
def show
product = Product.find_by(id: params[:id])
p "Is product nil? #{product.nil?}"
render json: product
end
If the object (product
in the snippet above) is nil
, then you may see the NoMethodError
reported above due to nil.read_attribute_for_serialization
being called.
Upvotes: 13
Reputation: 4592
I fixed my immediate problem by changing the custom serializer to RecordDetailSerializer and calling it from my show method in the controller. When I removed the include @JMazzy suggested it still worked. There is still something screwy. If I use the custom method in the index method:
def index
@records = Record.order('title')
render :json => @records, serializer: RecordDetailSerializer
end
I get the error on the missing id shown at the bottom of my question above. However, when I use it in my show method:
def show
@record = Record.find(params[:id])
render :json => @record, serializer: RecordDetailSerializer
end
If I remove the problem field, the next field in the list becomes the problem. This no a longer a problem for me as I can always limited custom serializers to and individual element.
Upvotes: 1
Reputation: 462
You need to add include ActiveModel::Serialization
to your model. Extended serialization is not included by default in ActiveModel. See this answer on GitHub.
Upvotes: 33