Cbas Cbas - 7 months ago 22
Ruby Question

has_many, through relationship not populating

I am trying to allow User modals to add and remove individual settings for other Users, but I cannot get the

has_many ... through
relationship to work correctly: I am able to create new Setting modals, but I cannot retrieve or delete them.

Here is my User.rb:

class User < ActiveRecord::Base
has_many :settings, class_name: "Setting",
foreign_key: "user_id",
dependent: :destroy

has_many :user_settings, through: :settings, source: :user

def create_settings(user)
settings.create(following_id: user.id)
end

def delete_settings(user)
settings.find_by(following_id: user.id).destroy
end

def has_settings?(user)
user_settings.include?(user)
end
...


Here is my Setting.rb:

class Setting < ActiveRecord::Base
belongs_to :user, class_name: "User"
validates :user_id, presence: true
validates :following_id, presence: true
end


I call the creation/deletion methods with these
users_controller
functions:

def add_settings
user = User.find(params[:user_id])
if !@user.has_settings?(user)
@user.create_settings(user)
@user.save
end
end

def remove_settings
user = User.find(params[:user_id])
if @user.has_settings?(user)
@user.delete_settings(user)
@user.save
end
end


If I call
add_settings
and then
remove_settings
I get a success response both times, but if I call
add_settings
again, I get the error:

ActiveRecord::RecordNotUnique (PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_settings_on_user_id_and_following_id"


So it seems
has_settings
in User.rb is always returning false and the user setting is never removed when the controller function
remove_settings
is called.

Why isn't the
user_settings
relationship being populated? How can I get
has_settings
to return the correct value?

Answer

user_settings.include?(user) will always return false, since user_settings is a collection of user_setting objects, not user objects. Furthermore, calling include? here might not be efficient as it requires loading multiple user_settings objects into memory to compare each one.

Depending on how user_settings, and settings are defined you should be able to use the following query to check if there are any user_settings which belong to this user (self). Try the following query:

def has_settings?(user)
  settings.exists?(following_id: user.id)
end