编辑 - 我确实误解了主键位,我认为希望告诉 Rails 使用不同的属性作为 PK,这应该比重新利用自动增量更容易- 默认情况下 PK ID。在这种情况下,Stage 模型应包括self.primary_key = "stage_number",以及与 HABTM 相关的答案底部的其余详细信息。当然 has-many-through 仍然是我首选的解决方案。
我认为模型和方法存在比 Rails Admin 更大的问题。
如果我理解您要执行的操作,那么您还需要关闭 stages 表中主键的自动增量,以将任意数字(表示阶段编号)作为主键 ID。它可能很快就结束了,所以我建议不要这样做。
如果数据真的是静态的(曾经有 10 个阶段),您甚至可以在 Band 模型中将其保持为常数并完全废弃 Stage(除非那里还有更多),例如
class Band < ActiveRecord::Base
POSSIBLE_STAGES = [1, 2, ...]
validates :stage, inclusion: { in: POSSIBLE_STAGES, message: "%{value} is not a stage we know of!" }
end
对于基于表的方法,我建议使用 has-many-through,它会在将来为您节省很多痛苦(即使您不需要连接表上的其他属性,例如嵌套表单比在 HABTM 中更容易使用)。像这样的:
class Band < ActiveRecord::Base
has_many :events
has_many :stages, through :events
# band details go into this model
end
class Event < ActiveRecord::Base
belongs_to :band
belongs_to :stage
# you could later add attributes here, such as date/time of event, used_capacity, attendee rating, and
# even validations such as no more than X bands on any given stage at the same time etc.
end
class Stage < ActiveRecord::Base
has_many :events
has_many :bands, through :events
# stage number/details go into this model
end
迁移可能看起来像这样:
create_table :bands do |t|
t.string :bandname
# whatever else
end
create_table :events do |t|
t.belongs_to :band
t.belongs_to :stage
# you could add attributes here as well, e.g. t.integer :used_capacity
end
create_table :stages do |t|
t.integer :number
t.integer :total_capacity
# whatever else
end
正如您所见,这里根本没有触及主键 ID,而且我总是避免将业务数据存储在 Rails 和任何类型的数据库管道中(这就是我认为的 ID,它们在那里确保关系数据库中数据的关系/完整性,以及与 ActiveRecord 的良好且一致的映射 - 所有业务数据都应除此之外,在实际属性中,而不是用于连接模型的管道)。
如果您仍然想要 HABTM 并重新调整主 ID 的用途,那么我认为 Stage 应该包含一个 foreign_key 语句来“宣传”自己到 bands_stages 连接表作为具有自定义键名(在 @ 987654332@ 仅),同时将association_foreign_key 保留在Band 端以显示要在连接表中查询的内容以到达另一端。 stages 表仍会使用 id 作为其主键,但您只想使用 t.integer :id, :options => 'PRIMARY KEY' 之类的东西关闭自动增量(可能取决于数据库风格 - 我再次建议不要这个)。
你的模型应该是这样的:
class Band < ActiveRecord::Base
has_and_belongs_to_many :stages, association_foreign_key: "stage_number"
end
class Stage < ActiveRecord::Base
has_and_belongs_to_many :bands, foreign_key: "stage_number"
end
bands 和 bands_stages 之间的连接将是 bands.id = bands_stages.band_id,为此会找到许多 bands_stages.stage_number,并且每个都将通过 bands_stages.stage_number = stages.id 连接到 stage(其中 stages.id 已重新- 旨在代表未来可能面临风险的业务数据)。