Cbas
Cbas

Reputation: 6213

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 [email protected]_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?

Upvotes: 1

Views: 91

Answers (1)

Anthony E
Anthony E

Reputation: 11235

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

Upvotes: 2

Related Questions