Matheus Santos
Matheus Santos

Reputation: 85

Why do I keep getting this ActiveRecord::AssociationTypeMismatch error?

I have two models that have a has_many association to the same object. I have a User, an Admin, and Visits.

Users has_many Visits Admins has_many Visits

Every time I create a Visit with a User it works, but when I do it with an Admin it gives me an error:

ActiveRecord::AssociationTypeMismatch.

The full error is this:

User(#70282715553200) expected, got #<Admin id: 2, email: "[email protected]", created_at: "2019-02-07 12:08:40", updated_at: "2019-02-07 12:08:40"> which is an instance of Admin(#70282709528720)

def create
  @visit = @service.visits.new(visit_params)

  if user_signed_in?
    @visit.user = current_user
  else
    @visit.user = current_admin
  end

  if @visit.save
    redirect_to service_visits_path(@service)
  else
    redirect_to @services
  end

end

==============================

class Admin < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and 
  # :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :visits, dependent: :destroy
end

==============================

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and 
  #  :omniauthable
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :validatable

  has_many :visits, dependent: :destroy
end

==============================

class Visit < ApplicationRecord
  belongs_to :user
  belongs_to :admin
  belongs_to :service
end

Upvotes: 2

Views: 439

Answers (2)

Jay Dorsey
Jay Dorsey

Reputation: 3662

Unless you've got some kind of polymorphism going on, which isn't documented, I'd try and change this:

if user_signed_in?
  @visit.user = current_user
else
  @visit.user = current_admin
end

To this:

if user_signed_in?
  @visit.user = current_user
else
  @visit.admin = current_admin # this line
end

Your Visit model says a visit has both one User, and one Admin, so you have to assign the current_admin to the @visit.admin, not @visit.user.

If you're using Rails 5, you'll also need to update your model as below:

class Visit < ApplicationRecord
  belongs_to :user, optional: true
  belongs_to :admin, optional: true
  belongs_to :service
end

As I note in my comment below, the suggestion from @bo-oz should be given considerable consideration. I haven't seen User and Admin tables typically split out as you've done in production applications. The concept of 'admin' is typically handled as a separate Role model (the rolify gem is good for this), or more simply as a boolean on the User model.

Upvotes: 2

bo-oz
bo-oz

Reputation: 2872

I think what you are trying to do us just plain wrong. An Admin is a User as well. You should remove the Admin model entirely. If you need to assign additional capabilities / rights to someone, you should either create an additional attribute (admin boolean yes/no), or create some kind of Role Based model. Have a look at Rolify gem.

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and 
:omniauthable
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :validatable

  has_many :visits, dependent: :destroy

  def is_admin?
    // return true if user is admin
  end
 end

class Visit < ApplicationRecord
  belongs_to :user
  belongs_to :service
end

def create
@visit = @service.visits.new(visit_params)

if user_signed_in?
  @visit.user = current_user
else

if @visit.save
  redirect_to service_visits_path(@service)
else
  redirect_to @services
end

One warning though.... the user is mandatory is this relationship, so this would break if someone is not logged in! Think about it... either don't create a Visit, or create an Anonynous visit.

Upvotes: 0

Related Questions