0

I'm attempting to approximate a polymorphic relationship in Rails 3 has-and-belongs-to-many association (HABTM).

The intersection table (user_favorites) has these fields: user_id, favorite_id, favorite_class

In the User class, I have the relationship defined:

  has_and_belongs_to_many :favorite_users, :class_name => "User", :join_table => "user_favorites", :association_foreign_key => "favorite_id", :foreign_key => "user_id", :conditions => "user_favorites.favorite_class='User'"

For retrieving data, this works as expected. Unfortunately, this definition won't add the favorite_class' value that I need ('User' in this situation).

Is there a way, perhaps using Arel, to set the favorite_class field to the desired value before the record is saved?

craig
  • 25,664
  • 27
  • 119
  • 205

3 Answers3

2

A has_many through association might work better. Here's an article that may help. It explains the problem with a polymorphic has_many :through relationship, and offers a workaround.

http://blog.hasmanythrough.com/2006/4/3/polymorphic-through

this might be helpful too:

Polymorphic habtm relationships with Rails/ActiveRecord

Community
  • 1
  • 1
Tim Stephenson
  • 830
  • 1
  • 7
  • 15
  • +1 habtm doesn't allow extra fields for the join association. It's frequently treated as deprecated, because changing the associations (from habtm to hmt) and code that uses them is a pain the first time an extra field is needed. has_many :through allows this without those major mods. – Michael Durrant Mar 03 '12 at 23:53
0

I was able to solve the problem by using the :insert_sql option (note use of single quotations):

:insert_sql => 'INSERT INTO user_favorites (user_id, favorite_id, favorite_type) VALUES (#{id}, #{record.id}, "User")'
craig
  • 25,664
  • 27
  • 119
  • 205
  • Not downvoting but I recommend against this. Rails depends on following the conventions. doing sql inserts like this is a PHP approach that is not recommended for professional production code. – Michael Durrant Mar 03 '12 at 23:56
0

You have SQL injection in your variant. Better use in your UserFavourites model following:

before_save :set_favourite_type

private 

def set_favorite_type
  self[:favorite_type] = self.favoritable.class.to_s
end

or at least use parametrized query instead of #{}

sandrew
  • 3,109
  • 5
  • 19
  • 29