I'd like to second this request -
I found myself fleshing out a lot of the details of my data base
structure using categories, salutations, image_types etc tables, which
I could then populate via a scaffold, and select in other tables using
a collection select. The problem is, when you want to go back and
alphabetize the categories list, for example, you get the record id's
changing, and then an object with a category_id of 12 is now pointing
to a different category than it was before (since you reordered the
table), which forces you to create after_save actions to update all
the objects that reference the categories table.
But if categories were in an xml/yml file, then their database table
id would be irrelevant etc.
The problem is, when you want to go back and
alphabetize the categories list, for example, you get the record id's
changing, and then an object with a category_id of 12 is now pointing
to a different category than it was before (since you reordered the
table), which forces you to create after_save actions to update all
the objects that reference the categories table.
What? I think you might be doing it wrong. You don't need to change
anything in the database to show the categories in alphabetical order:
No, I know. what i'm caying is, if you *do* somehow reorder the
categories, then your objects which reference them are all re-
categorized. that's bad - it's a dependency that is unnecessary.
what Scott was asking for originally was a way to enumerate options
without having to reference their position in a list. if you use a
database to create the list, then you necessarily have to reference
their position get to them, but if you define the list with, say, a
yml file, then position is irrelevant. So, you can alter the list at
will without having to worry about the consequences for objects which
reference the list - you just can't delete an item in the list.
From a design perspective, a more generic approach that preserves everything you know and love about AR models is to create the following tables/models:
Category
id
name
description
abbreviation
SystemType
id
category_id
name
description
abbreviation
Something like that. You can make SytemType acts_as_list if you like to order them, and categories can acts_as_tree if you want them to be hierarchically related. Knock yourself out. Can be as simple or complex as you wish to make it.
Category will have a one-to-many relationship with SystemType.
Where you would otherwise be tempted to add a table, instead add a Category record. When adding a new SystemType, you must relate it to a Category. The type system can grow without needing migrations.
You can also add static methods to SystemType to return all types for a given category. Let’s say one of those is ‘Image’ (denoting an image type), inside SystemType you can do something like this:
what Scott was asking for originally was a way to enumerate options
without having to reference their position in a list. if you use a
database to create the list, then you necessarily have to reference
their position get to them, but if you define the list with, say, a
yml file, then position is irrelevant. So, you can alter the list at
will without having to worry about the consequences for objects which
reference the list - you just can't delete an item in the list.
Nope, wrong. Primary key is not "position in a list". Please learn a
bit more about how SQL databases actually work.
Class Shape < ActiveRecord::Base
attr_accessible :color_id
belongs_to :color
end
Class Color < ActiveRecord::Base
has_many :shapes
end
Now, in the console:
sh = Shape.last
...
sh.color_id
12
sh.color.name
"red"
...
c = Color.find(12)
c.name = "blue"
c.save!
...
sh.color.name
"blue"
Oops! Now, every shape with shape.color_id =12 is now blue. You've
changed a Color, but inadvertently changed a Shape as well. That's
uncomfortable if not bad.
if you use a
database to create the list, then you necessarily have to reference
their position get to them
No - you reference their "primary key". This does not equate (unless
you have a *very* bad approach to DB design) to position.
but if you define the list with, say, a
yml file, then position is irrelevant.
No - again. If you have a yaml data source, you're probably going to
be storing a string value for the object. Exactly the same as if you'd
stored the string description (assuming the field was called
"description") of a db-table record. Absolutely no reference to
"position" is given.
So, you can alter the list at
will without having to worry about the consequences for objects which
reference the list - you just can't delete an item in the list.
If you're worried about referential integrity, then check for it
before allowing records to be deleted.
I have a strong feeling, Chewmanfoo, that you aren't grasping some of
the fundamental principles of SQL, and using relational databases to
store representations of objects.
Why would you *ever* change a colour's name? If it's blue it's blue.
It's immutable; atomic.
It's a value in a *lookup* table.
If you want to store the "name" of the colour instead of its id
(because you find yourself often doing hideous things like changing
the values in lookups), then do so; you'll just have a poor,
inflexible DB.
What he's saying is that it is "immutable" by policy. If you have a
database that stores orders where each order contains an order number
(not a primary key, but rather a number given to a customer), by policy
that order number should never change. If it did you would lose track of
the order.
This has nothing to do with position in the database. Order number is
simply a reference to one specific order. A reference that *must* be
immutable and atomic.
You are right, creating a database table for something like this does
feel like overkill. Personally, I often use constants if it's a very
small amount of data.
class Image
VALID_IMAGE_TYPES = ['png', 'gif', 'jpg']
end