Rails NoMethodError: undefined method `includes' for #<User:0x007f62dbbe62f8> - ruby-on-rails

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.

Related

Rails fires N+1 queries for polymorphic associations

I am using Rails 5.0.1, and am really confused about the following problem. I have few models with polymorphic associations.
class Container < ApplicationRecord
has_many :steps, as: 'parent', dependent: :destroy
end
class Step < ApplicationRecord
belongs_to :parent, polymorphic: true
belongs_to :implementation, polymorphic: true
end
class FirstStep < ApplicationRecord
has_one :step, as: 'implementation'
has_many :params, dependent: :destroy
end
class SecondStep < ApplicationRecord
has_one :step, as: 'implementation'
has_many :headers, dependent: :destroy
end
class Param < ApplicationRecord
belongs_to :first_step
end
class Header < ApplicationRecord
belongs_to :second_step
end
A step associates to an implementation (FirstStep, SecondStep). In addition to it, a container can also be a step's implementation. I'm using Active Model Serializers to serialize the model info to JSON. Following is the related code to serializers.
class StepSerializer < ActiveModel::Serializer
attributes :id, :implementation_type, :implementation_id, :active, :position
belongs_to :implementation
end
class FirstStepSerializer < ActiveModel::Serializer
attributes :name, :params_attributes
def params_attributes
object.params.map { |p| ParamSerializer.new(p).attributes }
end
end
class SecondStepSerializer < ActiveModel::Serializer
attributes :id, :title, :headers_attributes
def headers_attributes
object.headers.map { |p| HeaderSerializer.new(p).attributes }
end
end
class ParamSerializer < ActiveModel::Serializer
attributes :id
end
class HeaderSerializer < ActiveModel::Serializer
attributes :id
end
The implementations of step model can have different attributes, as specified in the model. The problem is, when I write
render json: container.steps
it fires N+1 queries to get the results. How do I optimize it?
Edit 1
Inspired by this answer, I tried to separate objects by their implementation_type, and it worked. What I did was:
# my controller action
def index
steps = []
steps += container.steps.where(implementation_type: 'FirstStep').includes(implementation: [:params])
steps += container.steps.where(implementation_type: 'SecondStep').includes(implementation: [:headers])
render json: steps
end
This prevented the N+1 queries for fetching params and headers, but it doesn't work if a step is a container.
Change your FirstStepSerializer and SecondStepSerializer serializer like following
class FirstStepSerializer < ActiveModel::Serializer
attributes :name
has_many :params, :serializer => ParamSerializer
end
class SecondStepSerializer < ActiveModel::Serializer
attributes :id, :title
has_many :headers, :serializer => HeaderSerializer
end
This might help

Rails Active Model Serializer not showing correct attributes

I'm not sure what I'm missing here, can anyone point me in the right direction? I set up the initializers and the associations in the model but my JSON is still returning only the attributes inside Active record, including the created_at and updated_at attributes. What am I doing wrong?
ApplicationController.rb
class ApplicationController < ActionController::API
include CanCan::ControllerAdditions
include ActionController::Serialization
acts_as_token_authentication_handler_for User
rescue_from CanCan::AccessDenied do |exception|
respond_to do |format|
format.json { render nothing: true, status: :forbidden }
end
end
end
CompanyController.rb
def show
#logo = Logo.find(params[:user_id])
render json: #logo
end
CompanyModel.rb
class Company < ActiveRecord::Base
belongs_to :user
has_one :logo, dependent: :destroy
has_many :cards, dependent: :destroy
end
LogoModel.rb
class Logo < ActiveRecord::Base
belongs_to :company
mount_uploader :image, ImageUploader
end
CompanySerializer.rb
module V1
class CompanySerializer < ActiveModel::Serializer
attributes :id, :user_id, :name
has_one :logo
end
end
LogoSerializer.rb
module V1
class LogoSerializer < ActiveModel::Serializer
attributes :id, :company_id, :image_url
end
end
EDIT: I should have posted the CompanyController Action, not the LogoController. I've added it above and added the LogoSerializer

Rails - Nested Strong parameters

I'm trying to create an user register using two models User and profile, nested strong parameters in one controller. when I send parameter I get this error unknown attribute 'profiles_attributes' for User. and I can't create user neither profile :
class User < ActiveRecord::Base
has_one :profile
has_many :apartments
has_many :session
has_secure_password
validates :email, presence: true, uniqueness: true
validates :password, presence: true
accepts_nested_attributes_for :profile
end
class Profile < ActiveRecord::Base
belongs_to :user
belongs_to :city
has_many :profile_universities
has_many :universities, through: :profile_universities
has_many :profile_preferences
has_many :preferences, through: :profile_preferences
has_one :photo, :as => :imageable
end
class Api::V1::UserController < ApplicationController
before_action :user_params
def create_without_facebook
#user= User.new(user_params)
if #user.save
#profile = Profile.new(user_params[:profiles_attributes])
render json: [#user, #profile]
else
render json: #user.errors, status: :unprocessable_entity
end
end
def user_params
params.require(:user).permit(:email, :password, profiles_attributes: [:first_name, :last_name, :birthday, :gender, :marital_status, :ocupation, :budget, :question, :about, :city])
end
end
use the singular profile_attributes if it's a has_one

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

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

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

Resources