views:

96

answers:

2

It occurred to me that if I have a has_many join, where the foreign model does not have a belongs_to, and so the join is one way, then I don't actually need a foreign key.

We could have a column, category_ids, which stores a marshaled Array of IDs which we can pass to find.

So here is an untested example:

class page < AR

  def categories
    Category.find(self.category_ids)
  end

  def categories<<(category)
    # get id and append to category_ids
    save!
  end

  def category_ids
    @cat_ids ||= Marshal.load(read_attribute(:category_ids)) rescue []
  end

  def category_ids=(ids)
    @cat_ids = ids
    write_attribute(:category_ids, ids)
  end

end

page.category_ids => [1,4,12,3] page.categories => Array of Category

Is there accepted pattern for this already? Is it common or just not worth the effort?

A: 

Wouldn't performance suffer here when you are marshalling / unmarshalling?

I personally don't think this is worth the effort and what you are trying to do doesn't seem clear.

Actually this looks like a many-to-many mapping rather than a many-to-one, as there is no code that prevents a category from belonging to more than one page, surely you want something like:

create table categories_pages (
  category_id integer not null references categories(id),
  page_id integer not null references pages(id),
  primary_key(category_id, page_id)
);

with either a has and belongs to many on both sides or has_many :through on both sides (depending on whether you want to store more stuff).

Omar Qureshi
I think it would be the equivalent of: page has_many categories. Because there is no chance of doing category.pages using this code. However a category could belong to more than one page, the Category model simply would never know. I'm not really touting this as an alternative to has_many or HABTM as its much more limited.There certainly would be a overhead to marshaling, I guess without testing we wouldn't know if it was greater than the magic performed by Rails to add a has_many relationship.
Kris
A: 

I agree with Omar that this doesn't seem to be worth the effort.

Your database no longer reflects your data model and isn't going to provide any help in enforcing this relationship. Also, you now have to keep your marshalled id array in sync with the Category table and enforce uniqueness across Pages if you want to restrict the relationship to has_many.

But I guess most importantly, what is the benefit of this approach? It is going to increase complexity and increase the amount of code you have to write.

Mike