Ruby/Rails - Check If Child Id Exists Within Record of HABTM Relationship
Asked Answered
P

4

6

I have a set of resources called Tasks and Posts and there are in a has_and_belongs_to_many (HABTM) relationship with each other.

There is also a join table connecting their values.

create_table 'posts_tasks', :id => false do |t|
   t.column :post_id, :integer
   t.column :task_id, :integer
end

So my question is how do I check to see if the id of a specific task exists within the array created from @post.tasks?

irb(main):011:0> @post = Post.find(1)
=> #<Post id: 2, comment: "blah blah", created_at: "2011-10-18 03:40:30", updated_at:
irb(main):012:0> @post.tasks
=> [#<Task id: 1, description: "Test 1", created_at: "2011-10-18 03:
   22:05", updated_at: "2011-10-18 03:22:05">, #<Task id: 3, description: "Test 3",
   created_at: "2011-10-18 03:22:21", updated_at: "2011-10-18 03:22:21
    ">]

So my question is whats the ruby way for writing does "@task = Task.find(2)" exist within @post.tasks and if so return true or false?

Poon answered 18/10, 2011 at 3:29 Comment(0)
A
10
@post.tasks.map(&:id).include?(task_id)

Where task_id is the id of the task you want to check. To explain this a little bit, you're taking the list of tasks, mapping them to an array of their ids, and then checking to see if the id in question is in that array. If you're not familiar with map you should check it out, it's awesome.

ruby-docs

Aney answered 18/10, 2011 at 3:46 Comment(1)
Just want to point out that this is not necessarily the best answer. The right way to do this will depend on what data you have already loaded, and what future questions you intend to ask of it. Database queries are expensive! Minimize them.Aney
C
13
@post.tasks.where(:id => task_id).present?

Is much lighter compared to what Gabelsman has suggested.

Courtship answered 18/10, 2011 at 5:32 Comment(2)
This makes n queries if you are checking n tasks. But still better than the accepted answer.Inofficious
It doesn't have to. You can pass an array of task_ids.Courtship
A
10
@post.tasks.map(&:id).include?(task_id)

Where task_id is the id of the task you want to check. To explain this a little bit, you're taking the list of tasks, mapping them to an array of their ids, and then checking to see if the id in question is in that array. If you're not familiar with map you should check it out, it's awesome.

ruby-docs

Aney answered 18/10, 2011 at 3:46 Comment(1)
Just want to point out that this is not necessarily the best answer. The right way to do this will depend on what data you have already loaded, and what future questions you intend to ask of it. Database queries are expensive! Minimize them.Aney
I
3

Assuming you named your has_and_belongs_to_many to :posts then doing something like this in Rails is very optimized:

@post.task_ids.include?(task.id)

I noticed that the two answer provided here result in n select statements. But doing it with task_ids caches the first query and the rest does not require a SELECT statement from the DB.

Inofficious answered 15/12, 2012 at 15:28 Comment(0)
D
2

You can use exists? method for that:

@post.tasks.exists?(id: task_id)
Douce answered 20/3, 2015 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.