Question

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?

Was it helpful?

Solution

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

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top