Hi! I'm a newbie wrapping my head around the Rails way of designing apps at the database layer, and I've hit a minor conceptual logjam and was hoping some of you might be able to help work me through it. I'm (re)designing a PHP audio jukebox in RoR (I'm going to be migrating a big pile of data from a system called Netjuke, which has been folded into the Jinzora project). I have some very definite ideas about how the data ought to be structured and how relationships ought to work, and the metadata schema I've designed generates lots of complicated dependencies and relationships which I feel are best specified and enforced at the database level. For now I'm working in PostgreSQL, but I might move this all over to Oracle at some point. So my toy version of the app has three classes of entities: artists, albums and tracks. Albums and tracks belong to artists (think compilations or soundtracks for why that notion of ownership needs to be at both levels) and tracks also belong to albums. I'm building the schema via migrations, but have slapped in migrations that look like: class AddConstraints < ActiveRecord::Migration def self.up execute 'ALTER TABLE tracks ADD FOREIGN KEY(album_id) REFERENCES albums ON DELETE RESTRICT' execute 'ALTER TABLE tracks ADD FOREIGN KEY(artist_id) REFERENCES artists ON DELETE RESTRICT' execute 'ALTER TABLE albums ADD FOREIGN KEY(artist_id) REFERENCES artists ON DELETE RESTRICT' end def self.down execute 'ALTER TABLE tracks DROP CONSTRAINT tracks_artist_id_fkey' execute 'ALTER TABLE tracks DROP CONSTRAINT tracks_album_id_fkey' execute 'ALTER TABLE albums DROP CONSTRAINT albums_artist_id_fkey' end end My problem is that using fixtures and transactional unit tests, I have to incorporate all the fixtures for the classes in the foreign key restrictions to ensure that fixtures get set up and torn down correctly. I.e. unless I have a line that says "fixtures :artists, :albums, :tracks" in test/unit/(album|artist|track)_test.rb, the test database isn't left in a sane state across unit tests and unit tests start failing due to integrity constraint errors when the fixture code tries to empty out the table during the fixture setup invoked by the fixtures method. It was a bit of an effort to figure all that out, and my solution feels hacky. Why should I have to set up fixtures for tracks and albums when I'm only testing artists, who sit at the top of this hierarchy? And how's that going to play when I add in many-to-many relationships between groups (artists) and their members? And glom genres onto this? It seems like this is going to make my test cases increasingly complex and unwieldy. Is it already time for me to abandon using "fixtures" in my test cases and start doing explicit fixture setup and teardown? Or is there a simple way I can modify the framework, e.g. to automatically clear out all of the fixtures used by an individual test case? I can't imagine I'm the only person who's run into this. Thanks in advance to any insight you might be able to provide. RoR is totally making it fun for me to work on this project again, and for that alone I'm very thankful. Forrest
on 2005-12-04 23:47
on 2005-12-05 03:34
Yeah, that's basically the deal, though it's not obvious from the RDocs. You can pre-populate the database before your tests run and use transactional_fixtures. Transactional fixtures are perhaps misnamed, as any database changes made by your tests roll back, but the fixtures do NOT. Fixtures are still deleted, inserted and committed for each test. I admit that I didn't like the approach either -- in previous Java projects, the team introduced nasty sequence problems in tests when we relied on pre-populated data. But after I fiddled with the order of my fixtures to account for foreign key constraints, it works fine and the transactions keep the test fast. Scott On Dec 4, 2005, at 2:47 PM, Forrest L Norvell wrote: > Hi! I'm a newbie wrapping my head around the Rails way of designing > apps > at the database layer, and I've hit a minor conceptual logjam and was > hoping some of you might be able to help work me through it. > > ...
on 2005-12-05 15:34
--- Scott Willson <firstname.lastname@example.org> wrote: > committed for each test. > > I admit that I didn't like the approach either -- in > previous Java > projects, the team introduced nasty sequence > problems in tests when > we relied on pre-populated data. But after I fiddled > with the order > of my fixtures to account for foreign key > constraints, it works fine > and the transactions keep the test fast. The approach also causes problems if you have triggers that disallow deletes from tables. We have data that we are required by law to only delete after 7, sometimes 20 years. So I created a trigger to prevent that from occuring. We ended up rewriting how the tests work from rake to building the schema from scratch every time. It fortunately only takes about 20 seconds. Shawn Garbett __________________________________________ Yahoo! DSL ? Something to write home about. Just $16.99/mo. or less. dsl.yahoo.com