Rails/Ember - active_model_serializer - undefined method `object' when sideloading - ruby-on-rails

I'm trying to sideload data in active_model_serializer for an Ember application and get a NoMethodError when I attempt to include the objects:
undefined method `object' for #Email:0x00000100d33d20
It only happens when :include => true is set, like this:
class ContactSerializer < ActiveModel::Serializer
embed :ids, :include => true
attributes :first_name, :last_name
has_many :emails
end
My models look like this:
class Contact < ActiveRecord::Base
attr_accessible :first_name, :last_name, :company,
belongs_to :account
belongs_to :user
has_many :emails
end
class Email < ActiveRecord::Base
attr_accessible :email_address, :email_type_id, :is_primary
belongs_to :contact
end
My controller looks like this:
def show
#contact = #current_user.contacts.where(:id => params[:id]).includes(:emails).first
render :json => #contact
end
Thanks in advance.

As Deefour mentioned above, make sure you have a serializer for any sideloaded objects. In this case, creating EmailSerializer:
class EmailSerializer < ActiveModel::Serializer
attributes :id, :email_address
end

Related

Rails NoMethodError: undefined method `includes' for #<User:0x007f62dbbe62f8>

I'm using the active_model_serializers gem in my Rails 5 app. I created a few serializer files in /app/seralizers, user_serializer.rb, sector_serializer.rb, and slot_serializer.rb .
class UserSerializer < ActiveModel::Serializer
attributes :id, :first_name, :last_name, :email, :phone, :admin, :auth_token, :organization_id
has_many :sectors
has_many :slots
has_many :elements
end
class SectorSerializer < ActiveModel::Serializer
attributes :id, :user_id, :sector_number, :title
belongs_to :user
has_many :slots
has_many :elements
end
class SlotSerializer < ActiveModel::Serializer
attributes :id, :user_id, :sector_id, :sector_number, :title, :slot_number
belongs_to :user
belongs_to :sector
has_many :elements
end
And in my controller code, I have:
class Api::V1::UsersController < API::V1::BaseController
respond_to :json
def sky
#user = User.find_by_id(params[:user_id]).includes(:sectors, :slots)
if #user
render json: #user
else
raise "Unable to get Sky"
end
end
end
My server is throwing an error at the line where I do the .includes and I can't figure out why.
Any help is appreciated. Thanks!
Change
#user = User.find_by_id(params[:user_id]).includes(:sectors, :slots)
to
#user = User.includes(:sectors, :slots).find_by_id(params[:user_id])
Point is you have to call includes on a class (that inherits from ActiveRecord::Base/ApplicationRecord), not a single user object.

Rails has_many through validation got skipped

I'm feeling a little bit dumb to ask this, but I've been Googling my a*# off.
Well I have the following models:
class Company < ActiveRecord::Base
has_many :employments
has_many :users, through: :employments
validates_presence_of :name
validates_presence_of :description
validates_numericality_of :zip, only_integer: true
validates_presence_of :email
validates_presence_of :street
validates_presence_of :city
validates_presence_of :country
validates_presence_of :telephone
end
class Employment < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
class User < ActiveRecord::Base
has_many :employments
has_many :companies, through: :employments
end
Important here is the company-Model which has some validations.
Now, I have the following Controller to create a new Company:
class CompaniesController < ApplicationController
def create
#company = Company.new(company_params) # The params were set with a private Method
#employment = #company.employments.build(user: current_user, is_admin: true)
if #employment.save
redirect_to :back, flash: { success: 'Success' }
else
#title = 'Create a new company'
render :new
end
end
end
The Problem is, that when I leave the companies-Fields blank, the company gets not created, but the employment-Model gets persistet in the Database.
I believe It has something to do with the Company.new()-Call I have to check, if the #company-Model gets created first, before the #employment-Model gets created.
How can I achieve that the validation gets tested first?
Thank you very much!
To validate associated object you need to use validates_associated. Please note the "Warning" and "Note" in the linked api document.
Try:
class Employment < ActiveRecord::Base
belongs_to :user
belongs_to :company
validates_associated :company
end
in addition to vinodadhikary's answer, you can also try saving the company. so instead of #employment.save, use #company.save. That should also save #employment when #company passes validations.

Serialize delegate in rails

I have 3 models in Rails: User, UserProfile and Post
Something like this:
class Post < ActiveRecord::Base
attr_accessible :content, :post_type
belongs_to :user
delegate :fullname, :to => :user, :prefix => "author"
end
class User < ActiveRecord::Base
has_many :posts
has_one :user_info
delegate :fullname, :to => :user_info
end
class UserInfo < ActiveRecord::Base
attr_accessible :avatar, :fullname, :birthday, :nickname, :gender, :about
belongs_to :user
end
Now I use knockout to manage posts at client-side so I have to make my object to json using posts.to_json. These JSON objects don't have attributes fullname. I tried with user.to_json, and these objects don't have that attribute either. So how can I make the delegate serialize to JSON?
Since fullname is a virtual attribute in the sense:
Rails 2:
posts.to_json(:method => %w(fullname))
user.to_json(:method => %w(fullname))
Rails 3:
posts.to_json(:methods => %w(fullname))
user.to_json(:methods => %w(fullname))

Active Model Serializers belongs_to

This question pertains to AMS 0.8
I've got two models:
class Subject < ActiveRecord::Base
has_many :user_combinations
has_ancestry
end
class UserCombination < ActiveRecord::Base
belongs_to :stage
belongs_to :subject
belongs_to :user
end
And two serializers:
class UserCombinationSerializer < ActiveModel::Serializer
attributes :id
belongs_to :stage
belongs_to :subject
end
class SubjectSerializer < ActiveModel::Serializer
attributes :id, :name, :description, :subjects
def include_subjects?
object.is_root?
end
def subjects
object.subtree
end
end
When a UserCombination is serialized, I want to embed the whole subtree of subjects.
When I try to use this setup I get this error:
undefined method `belongs_to' for UserCombinationSerializer:Class
I tried changing the UserCombinationSerializer to this:
class UserCombinationSerializer < ActiveModel::Serializer
attributes :id, :subject, :stage
end
In this case I get no errors, but the subject is serialized in the wrong way - not using the SubjectSerializer.
My questions:
Shouldn't I be able to use a belongs_to relation in the serializer?
If not - how can I get the wanted behaviour - embedding the subject tree using the SubjectSerializer?
This is not really elegant but it seems to be working :
class UserCombinationSerializer < ActiveModel::Serializer
attributes :id, :stage_id, :subject_id
has_one :subject
end
I don't really like calling has_one whereas it's actually a belongs_to association :/
EDIT: Disregard my comment about has_one/belongs_to ambiguity, the doc is actually pretty clear about it: http://www.rubydoc.info/github/rails-api/active_model_serializers/frames
In Active Model Serializer 0-10-stable, belongs_to is now available.
belongs_to :author, serializer: AuthorPreviewSerializer
belongs_to :author, key: :writer
belongs_to :post
belongs_to :blog
def blog
Blog.new(id: 999, name: 'Custom blog')
end
https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/serializers.md#belongs_to
So you could do:
class UserCombinationSerializer < ActiveModel::Serializer
attributes :id
belongs_to :stage, serializer: StageSerializer
belongs_to :subject, serializer: SubjectSerializer
end
What if you try with something like this:
class UserCombinationSerializer < ActiveModel::Serializer
attributes :subject,
:stage,
:id
def subject
SubjectSerializer.new(object.subject, { root: false } )
end
def stage
StageSerializer.new(object.stage, { root: false } )
end
end

Received ActiveRecord Relation, but need object

i've written the following classes:
class Occupation < ActiveRecord::Base
has_many :pref_labels
has_many :cv_occupations
has_many :cvs, :through => :cv_occupations
validates_uniqueness_of :uri
# This function will return the specified label for the given language.
def label(language = Language.find_or_create_by_code(:en))
self.pref_labels.where("language_id = #{language.id}")
end
end
class PrefLabel < ActiveRecord::Base
belongs_to :language
belongs_to :concept
belongs_to :skill
belongs_to :occupation
validates_uniqueness_of :value, :scope => [:language_id, :value]
validates_uniqueness_of :language_id, :scope => [:language_id, :value]
end
In my view, I call the following: %td= occupation.label(#language)
but this returns as error :
undefined method `value' for #<ActiveRecord::Relation:0x80c8368>
How can I get the actuall object returned instead of the relation? I know this has something to do with the lazy loading....
Change
self.pref_labels.where("language_id = #{language.id}")
To
self.pref_labels.where("language_id = #{language.id}").all #or .first if you only one the first one

Resources