开发者

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

开发者 https://www.devze.com 2023-01-27 09:36 出处:网络
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

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(:us开发者_开发技巧er=>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?


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?


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....


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号