uv.
uv.

Reputation: 344

When, if ever, should an association's ID be used directly?

Say I have a User model, a Task model that belongs_to :user, :has_one :event, has a completed boolean attribute, and an Event model that is created when a task is completed, and also belongs_to :event.

In the TaskObserver I've noticed that instead of

# app/controllers/task_observer.rb
class TaskObserver < ActiveRecord::Observer
def after_update(task)
  def after_update
    task.create_event(:user=>task.user) if task.completed?
  end
end

I could write

task.create_event(:user_id=>task.user.id)

or even

task.create_event(:user_id=>task.user_id)

While the first way seems the most correct, are there benefits to using either of the latter variations?

Upvotes: 3

Views: 67

Answers (3)

uv.
uv.

Reputation: 344

In this specific case I went with task.create_event(:user_id=>task.user_id). By running:

$ rails c
ruby-1.8.7-p299 > ActiveRecord::Base.logger = Logger.new(STDOUT)
ruby-1.8.7-p299 > Task.where("user_id IS NOT NULL).user.id
...
User Load (1.2ms)  SELECT `users`.* FROM `users` WHERE (`users`.`id` = 103) LIMIT 1
=> 103

you can see that Rails will actually load the User from the database. Even if it was cached, I don't see why I should handle the actual objects if I'm just copying a reference.

So in general, I think it's preferred to use objects when you've used them before, and IDs when you didn't and don't plan to.

Upvotes: 1

Cory
Cory

Reputation: 2538

As Beerlington said - there is no "right" or "wrong" here - perhaps a performance consideration to be had however...

In the task.user.id case, if the user isn't eager-loaded, you're making a round trip to the database; in the task.user_id case, you're not making that round trip....

  • Note - Rails is probably smart enough to notice that if you're just grabbing id off the association it can just use task.user_id - but I haven't gone to great lengths to confirm this. Would be easy enough to check against the development.log....

Upvotes: 2

Peter Brown
Peter Brown

Reputation: 51697

In Rails, associations can be assigned either way, neither is "right" or "wrong" and it's just the nature of the framework. The models has setter methods for both user_id and user, which is why you can use either without any noticeable difference.

The way you are creating events seems a little strange to me though. It seems really odd that a task would belong_to an event, but the event is only created when the task is complete. Is that really how it works?

Upvotes: 2

Related Questions