Reputation: 472
I have a Task
model and User
model, I have a join table b/w Task
& User
named Tag
.
Task.rb
class Task < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
has_many :tags, dependent: :destroy
validates :description, presence: true
def tagged_user_ids
tags.map{|tag| tag.user_id}
end
def tag_exists_for(user)
tagged_user_ids.include?user.id.to_s
end
def tag(user)
tags.create(user_id: user.id)
end
def untag(user)
tags.find_by(user_id: user.id).destroy
end
end
User.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :tasks
has_many :tags
has_many :comments,through: :tasks
def tagged_tasks
tags.map{|tag| tag.task}
end
def all_tasks
self.tasks + self.tagged_tasks
end
end
Tag.rb
class Tag < ActiveRecord::Base
belongs_to :user
belongs_to :task
end
I wrote the following test case for the untag method
describe "untag" do
it "should untag user from task" do
create_task_and_tag_user
p @task2.tags
@task2.untag(@user)
p @task2.tags
expect(@task2.tag_exists_for(@user)).to be false
end
end
def create_task_and_tag_user
@user = User.create(email:"[email protected]",password: 123456,name: "user1")
@task1 = @user.tasks.create(description: "some description")
@user2 = User.create(email:"[email protected]",password: 123456,name: "user2")
@task2 = @user2.tasks.create(description: "some other task")
@task2.tag(@user)
end
but this test fails
Task untag should untag user from task
Failure/Error: expect(@task2.tag_exists_for(@user)).to be false
expected false
got true
on further investigation, i found out that untag(tag)
deletes tag record,but when i call task.tags it shows in the collectionproxy
Tag.find_by(id: 39)
Tag Load (0.3ms) SELECT `tags`.* FROM `tags` WHERE `tags`.`id` = 71 LIMIT 1
=> nil
2.4.1 :042 > t1.tags
=> #<ActiveRecord::Associations::CollectionProxy [#<Tag id: 39, user_id: "3", task_id: "37", created_at: "2018-01-18 11:13:23", updated_at: "2018-01-18 11:13:23">, #<Tag id: 43, user_id: "9", task_id: "37", created_at: "2018-01-22 04:56:13", updated_at: "2018-01-22 04:56:13">, #<Tag id: 44, user_id: "5", task_id: "37", created_at: "2018-01-22 05:31:16", updated_at: "2018-01-22 05:31:16">]>
2.4.1 :043 >
I come from a Mongodb,nosql background so never experienced this kind of behaviour before. Is there a way i can deleted associations also(without using any gem, some suggested to use paranoia gem and replace destroy by really_destroy!)
Upvotes: 2
Views: 600
Reputation: 2088
This happened because Tag objects that you destroyed are still cached in ruby. That is why reload
solved the issue, because it re-fetches tags from the database.
To have a little performance boost and not have to call reload
in tests, I would suggest rewriting the method tagged_user_ids
this way:
def tagged_user_ids
tags.pluck(:user_id)
end
First of all, this will call an SQL query to only fetch user_id
column instead of all columns. Secondly each call to this method will execute a new SQL query, in which case if you delete some tags, this method will reflect the result without calling reload
on task object.
Another unrelated improvement would be rewriting tagged_tasks
into:
has_many :tagged_tasks, through: :tags
Upvotes: 2