I have several simple many-to-many relationships in my app. Some use
a join model, and others don’t. Let’s start with one that doesn’t.
class Company < ActiveRecord::Base
has_and_belongs_to_many :industries
Add an industry if it isn’t already there
def add_industry(name)
name.strip!
unless self.industries.find_by_name(name)
industry = Industry.find_or_initialize_by_name(name)
self.industries << industry
end
end
end
I have three tables: companies, industries, and companies_industries.
The problem I have is best practices to handle errors with habtm and
Ruby. There are several things that could go wrong here. First,
there should be an update lock on the initial find to ensure that two
processes don’t try to add the same industry. Does :lock => true work
properly here? Normally, I use that where I want to lock a single
row, but that’s not what is happening here.
The next problem is how to get errors from self.industries <<
industry. Both industries and company_industries are inserted into
with this statement. I usually try to use create! and save! in case
there is some db error, but I don’t have that option here. Won’t this
fail silently or by returning nil? If it returns nil, I do I know
what failed?
What are the best practices for making this bulletproof? Note, I’m
old-school enough want to know what is going on under the covers and
protect my app from it.
there should be an update lock on the initial find to ensure that two
processes don’t try to add the same industry. Does :lock => true work
properly here? Normally, I use that where I want to lock a single
row, but that’s not what is happening here.
A unique index on companies_industries can be used to enforce the
uniqueness. :lock => true locks an individual record, but that’s not
what you want here. Depending on your database there may be other
things you can do with regard to locking.
The next problem is how to get errors from self.industries <<
industry. Both industries and company_industries are inserted into
with this statement. I usually try to use create! and save! in case
there is some db error, but I don’t have that option here. Won’t this
fail silently or by returning nil? If it returns nil, I do I know
what failed?
Looking at the source, the return value of the call to << will be
false if somethng funny happened.
I have the unique index, but it looks like self.industries << industry
doesn’t give me a way to know why it returned false. That’s too bad.
It would be nice to raise an exception with more information.
Is it standard practice in rails to ignore these errors? Previous web
apps I did a lot with stored procs so I had more control and info.