什么是合适的模型关联?

What would be the appropriate model association?

我有一个 Organization 和 Actioncode 模型。注册高级帐户时,组织可以输入折扣代码。因此,一个组织没有使用或使用了 1 个操作代码,而一个操作代码可以被许多组织使用。

当前关联:

Organizations migration file:  t.references :actioncode,   index: true,    foreign_key: true
Organization model:            belongs_to :actioncode
Actioncode model:              has_many :organizations

此设置的初始问题:actioncode_id 不应该是强制性的 在播种时我曾经得到错误代码 ActiveRecord::AssociationTypeMismatch: Actioncode(#23575660) expected, got Fixnum(#5494220)。原因似乎是 actioncode_id 已成为组织模型中的必填列。事实并非如此; actioncode 也应该可以是 nil,因为组织在支付高级帐户时也可以 而不是 use/have 任何 actioncode。

当前情况:升级到 PostgreSQL: 作为回应,我已经将我的数据库升级到 PostgreSQL。尽管如此,现在在迁移时我收到错误消息(请参阅 post 底部的完整消息):

PG::UndefinedTable: ERROR: relation "actioncodes" does not exist

错误信息:知道是什么导致了这个错误吗?删除 'current association' 下的三行,我的迁移和播种没有问题。事实上,保留所有三行但从第一行删除 index: true, foreign_key: true 并且它也可以正确迁移。当我保持 index: true 迁移时,它给出了错误:SyntaxError: xxx_create_organizations.rb:17: syntax error, unexpected tSYMBEG, expecting => t.boolean :activated。当我保留 foreign_key: true 时,它会产生原始错误消息 PG::UndefinedTable.

如果我将第一行更改为不正确的代码:t.references :actioncode_id, index: true, foreign_key: true,则会出现以下错误:

PG::UndefinedTable: ERROR:  relation "actioncode_ids" does not exist
: ALTER TABLE "organizations" ADD CONSTRAINT "fk_rails_604f95d1a1"
FOREIGN KEY ("actioncode_id_id")
  REFERENCES "actioncode_ids" ("id")

所以给定最后一行的 _ids,Rails 不知何故似乎对 table 的名称有问题。将 self.table_name = 'actioncodes' 添加到动作代码模型文件没有任何区别。怎么办?


替代协会:

我想知道我是否需要一个替代协会来满足我的需要。我调查了其他几个协会,但不确定该怎么做。最好的情况我在组织模型中只有一列包含使用的操作代码,或者如果没有使用操作代码则为 nil。我需要一个模型关联,例如打印所有使用特定操作代码的组织。

替代关联 1:此关联的问题是 actioncode 仍然是组织模型中的强制变量,因此不能为 nil。

Organization migration:  t.references :actioncode,   index: true,    foreign_key: true
Organization model:      has_one :actioncode
Actioncode model:        has_many :organizations

替代关联 2: 该关联将在操作代码 table 中包含 organization_id(我猜是一个数组),而从我的角度来看它将 actioncode_id 包含在组织 table 中会更有意义。此外,下面的代码仍然需要每个组织的操作代码。

Organization model:          has_one :actioncode
Actioncodes migration file:  t.belongs_to :organization, index: true

替代关联 3: 我也考虑过创建一个额外的关联模型,但这让我怀疑我在遵循这个策略时是否没有想太多,因为这会增加一个额外的 table/model。另外,我不确定下面的组织模型是否仍然需要折扣值,从而不能真正解决原来的问题。但如果这是要走的路,我在想:

Organization model:    has_one :discount
                       has_one :actioncode, through: :discount
Discount model:        belongs_to :organization
                       has_one :actioncode
Actioncode model:      belongs_to :discount
Discount migration:    t.belongs_to :organization, index: true
                       doesn;t need any other columns
Actioncode migration:  t.belongs_to :discount, index: true

替代关联 4: 最后,has_and_belongs_to_many 关联对我来说没有意义,因为我理解它是为了 many:many 关系,而 organization:actioncode 是 many:1/0 关系。

我应该使用什么设置并且没有将 actioncode 作为组织的强制变量?


附加信息: 运行 rake db:migrate rake db:droprake db:create 之后的 SQL:

== 20150410153815 CreateUsers: migrating ===============================
-- create_table(:users)
   -> 0.0582s
== 20150410153815 CreateUsers: migrated (0.0628s) ======================

== 20150410200022 AddIndexToUsersEmailAndUsername: migrating ===========
-- add_index(:users, :email, {:unique=>true})
   -> 0.0109s
-- add_index(:users, :username, {:unique=>true})
   -> 0.0100s
== 20150410200022 AddIndexToUsersEmailAndUsername: migrated (0.0219s) ==

== 20150416113853 CreateOrganizations: migrating ==============================
-- create_table(:organizations)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  relation "actioncodes" does not exist
: ALTER TABLE "organizations" ADD CONSTRAINT "fk_rails_4ecaa2493e"
FOREIGN KEY ("actioncode_id")
  REFERENCES "actioncodes" ("id")
/usr/local/rvm/gems/ruby-2.1.5/gems/activerecord-4.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:155:in `async_exec'
<<SNIP>>
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "actioncodes" does not exist
: ALTER TABLE "organizations" ADD CONSTRAINT "fk_rails_4ecaa2493e"
FOREIGN KEY ("actioncode_id")
  REFERENCES "actioncodes" ("id")
/usr/local/rvm/gems/ruby-2.1.5/gems/activerecord-4.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:155:in `async_exec'
<<SNIP>>

附加信息: SQL 从迁移 运行 当前关联(运行 rake db:drop 然后 rake db:setup):

-- enable_extension("plpgsql")
   -> 0.0664s
-- create_table("actioncodes", {:force=>:cascade})
   -> 0.0412s
-- add_index("actioncodes", ["actioncode"], {:name=>"index_actioncodes_on_actioncode", :unique=>true, :using=>:btree})
   -> 0.0217s
-- create_table("organizations", {:force=>:cascade})
   -> 0.0237s
-- add_index("organizations", ["summ"], {:name=>"index_organizations_on_summ", :unique=>true, :using=>:btree})
   -> 0.0106s
-- add_index("organizations", ["name"], {:name=>"index_organizations_on_name", :unique=>true, :using=>:btree})
   -> 0.0197s
<<SNIP, OTHER TABLES >>
-- initialize_schema_migrations_table()
   -> 0.0352s
-- enable_extension("plpgsql")
   -> 0.0405s
-- create_table("actioncodes", {:force=>:cascade})
   -> 0.0176s
-- add_index("actioncodes", ["actioncode"], {:name=>"index_actioncodes_on_actioncode", :unique=>true, :using=>:btree})
   -> 0.0085s
-- create_table("organizations", {:force=>:cascade})
   -> 0.0148s
-- add_index("organizations", ["summ"], {:name=>"index_organizations_on_summ", :unique=>true, :using=>:btree})
   -> 0.0113s
-- add_index("organizations", ["name"], {:name=>"index_organizations_on_name", :unique=>true, :using=>:btree})
   -> 0.0195s
<<SNIP, OTHER TABLES >>
-- initialize_schema_migrations_table()
   -> 0.0342s
rake aborted!
ActiveRecord::AssociationTypeMismatch: Actioncode(#39911240) expected, got Fixnum(#20092360)
/usr/local/rvm/gems/ruby-2.1.5/gems/activerecord-4.2.1/lib/active_record/associations/association.rb:216:in `raise_on_type_mismatch!'
<<SNIP >>

你这里有一个 logic/flow 问题。

Organization 不应该属于 Actioncode,如果 Organization 可以 拥有 一个代码。或不。这就是为什么

组织

has_one :actioncode

动作代码

belongs_to :organization

那样 Organization 不会保持 actioncode_id,但 Actioncode 会保持 organization_id

更新:

按照我上面提到的那样做,让 Actioncode 拥有一个 typevalue 字段,例如包含 'AC-08821' 字符串。这样你就可以保持这两个模型之间的预期关系并且仍然能够例如搜索具有相同 value.

的所有代码

创建关联 table,例如使用 has_and_belongs_to_many

更多信息在这里:http://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many

基本上你创建另一个 table 代表两个模型之间的联系。

基于“...一个组织没有或有 1 个 actioncode 并且一个 actioncode 可以被许多组织使用”,您的建模是正确的,只是迁移创建的外键没有actioncode_id 列中允许空值。您可以检查迁移 SQL 以查看使用了什么命令。

也许您使用的数据库不允许外键列为零,但大多数都允许。为了允许空值,您可能必须使用 SQL 而不是 Rails 构造外键。

来自 postgresql 文档:http://www.postgresql.org/docs/9.3/static/ddl-constraints.html

Now it is impossible to create orders with non-NULL product_no entries that do not appear in the products table.

请注意,“...具有非 NULL product_no 条目...”,空条目应该没问题,并且您的建模是正确的。