我有Task
模型和User
模型,我有一个联接表b / w Task
& User
名为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
我为untag方法编写了以下测试用例
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:"asd@jaka.com",password: 123456,name: "user1")
@task1 = @user.tasks.create(description: "some description")
@user2 = User.create(email:"user2@jaka.com",password: 123456,name: "user2")
@task2 = @user2.tasks.create(description: "some other task")
@task2.tag(@user)
end
但此测试失败
Task untag should untag user from task
Failure/Error: expect(@task2.tag_exists_for(@user)).to be false
expected false
got true
在进一步调查中,我发现untag(tag)
删除了标记记录,但是当我调用task.tags时,它会显示在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 >
我来自Mongodb,nosql背景,所以从未经历过这种行为。 有没有办法我可以删除关联(不使用任何宝石,一些建议使用偏执宝石,并用really_destroy替换销毁!)
答案 0 :(得分:1)
这是因为您销毁的Tag对象仍然在ruby中缓存。这就是reload
解决问题的原因,因为它从数据库中重新获取标签。
为了提高性能而不必在测试中调用reload
,我建议用这种方式重写方法tagged_user_ids
:
def tagged_user_ids
tags.pluck(:user_id)
end
首先,这将调用SQL查询仅提取user_id
列而不是所有列。其次,对此方法的每次调用都将执行一个新的SQL查询,在这种情况下,如果删除某些标记,此方法将反映结果而不在任务对象上调用reload
。
另一个不相关的改进是将tagged_tasks
重写为:
has_many :tagged_tasks, through: :tags