Christian
Christian

Reputation: 638

Callback before association is called

I have to set the table name of an associated model (limesurvey), because the table name is dynamic and depends on an attribute (survey_id) of the model (task).

My current implementation sets the table name, when the task is initialized:

class task < ActiveRecord::Base
  after_initialize :setTablename
  has_one :limesurvey

  def setTablename
    Limesurvey.table_name = "lime_survey_#{self.survey_id}"
  end
end

This implementation works, but it has the disadvantage, that the setTablename-method is called for every task, although it isn't needed.

How can I execute setTablename only before the association limesurvey is loaded?

Upvotes: 2

Views: 177

Answers (2)

Andrew Haines
Andrew Haines

Reputation: 6644

Associations are just methods defined in a module that is included in your model, so you can override them as you would other methods

class Task < ActiveRecord::Base
  has_one :limesurvey

  def limesurvey
    # do something here...

    super
  end
end

However, as people have mentioned in the comments on the question, what you're doing is a really bad idea. What would happen if you have two tasks available at once, and attempted to access the limesurvey on both of them?

t1 = Task.first
t2 = Task.last

l1 = t1.limesurvey
l2 = t2.limesurvey

l1.update_attributes(foo: "bar")
# Oops... saves into the wrong table...

Even if you manage to avoid doing this explicitly anywhere in your whole app, if you have two concurrent requests it could potentially happen accidentally!

Upvotes: 0

Marlin Pierce
Marlin Pierce

Reputation: 10099

Caveat: I agree that you are taking on a sea of troubles as the commenters have mentioned. Further, this will likely be worse, since before at lease setTablename was getting called for every task.

class Task < ActiveRecord::Base
  has_one :limesurvey

  def lime_survey
    @table_name || = (Limesurvey.table_name = "lime_survey_#{self.survey_id}")

    limesurvey
  end
end

This defines a version of limesurvey with an underscore, but checks first if the table name has been set. Call lime_survey instead of limesurvey, and you will have the effect you asked for.

Similar to the approach suggested by Andy. However, although the association is just a method, I'm not sure you can redefine it and call super, since it's not a method in the parent class (or module).

Upvotes: 2

Related Questions