什么是合适的模型关联?

时间:2015-05-06 10:45:44

标签: ruby-on-rails ruby postgresql ruby-on-rails-4 associations

我有一个组织和动作代码模型。注册高级帐户时,组织可以输入折扣的操作码。因此,组织使用了no或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,因为在支付高级帐户时,组织也可以使用/拥有任何操作码。

当前情况:升级到PostgreSQL之后:作为回应,我已将我的数据库升级为PostgreSQL。然而,现在在迁移时我收到错误消息(请参阅帖子底部的完整消息):

  

PG :: UndefinedTable:ERROR:relation" actioncodes"不存在

错误消息:有什么想法导致此错误?删除'当前关联'下的三行。我对迁移和播种没有任何问题。事实上,保留所有三行但从第一行删除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似乎确实遇到了表名的问题。将self.table_name = 'actioncodes'添加到动作代码模型文件没有任何区别。怎么办?

替代协会:

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

替代关联1:此关联的问题在于,操作码仍然是组织模型中的必需变量,因此不能为零。

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

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

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

另类关联3:我还考虑过创建一个额外的关联模型,但这让我想知道当我遵循这个策略时,我是否不会过度思考,因为这样做会添加一个额外的表/模型。另外,我不确定下面的组织模型是否仍然需要折扣价值,因此不能真正解决原始问题。但如果这是可行的方法,我想:

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协会对我来说没有任何意义,因为我理解它的目的是为了很多:许多关系,而组织:actioncode是一个很多:1/0的关系。

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

其他信息:在rake db:migraterake db:drop之后运行rake 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 >>

2 个答案:

答案 0 :(得分:1)

这里有逻辑/流量问题。

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

组织

has_one :actioncode

Actioncode

belongs_to :organization

这样Organization不会保留actioncode_id,但Actioncode会保留organization_id

<强>更新

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

创建关联表,例如使用has_and_belongs_to_many

此处有更多信息:http://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many

基本上,您创建另一个表,表示两个模型之间的连接。

答案 1 :(得分:1)

基于,“......组织没有或1个动作代码,许多组织都可以使用动作代码”,您的建模是正确的,只是迁移创建的外键不允许空值在actioncode_id列中。您可以检查迁移SQL以查看使用的命令。

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

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

  

现在无法使用未出现在products表中的非NULL product_no条目创建订单。

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