Reputation: 85
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
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
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