【问题标题】:What would be the appropriate model association?什么是合适的模型关联?
【发布时间】:2015-05-06 10:45:43
【问题描述】:

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

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

PG::UndefinedTable: 错误:关系“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: 这种关联的问题在于 actioncode 在组织模型中仍然是强制变量,因此不能为 nil。

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

替代关联 2: 该关联会将 organization_id 保存在 actioncodes 表中(我猜是一个数组),而从我的角度来看,将 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 关联对我来说没有意义,因为我如何理解它是针对多:多关系的,而组织:操作代码是多:1/ 0 关系。

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


附加信息:rake db:droprake db:create之后运行rake db:migrate的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 >>

【问题讨论】:

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


    【解决方案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 条目...”,null 条目应该没问题,并且您的建模是正确的。

    【讨论】:

    • 谢谢,所以我想我应该先升级到 PostgreSQL 来测试它是否可以工作。我已经在生产中使用它,但在开发中使用 SQLite。升级后我会回帖(到目前为止没有成功:stackoverflow.com/questions/30233999/…
    • 是的,您绝对应该使用相同的数据库进行开发和生产。
    • 我已经升级到 PostgreSQL。我使用rake db:drop,然后使用rake db:setup,代码中包含原始帖子开头的三行。不幸的是,在播种时我仍然收到相同的错误消息。
    • 能否展示迁移创建表和添加外键时使用的SQL
    • 我已将迁移的 SQL 添加到原帖中。我省略了其他表的 SQL(包括操作代码和组织)。
    【解决方案2】:

    这里有逻辑/流程问题。

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

    组织

    has_one :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

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

    【讨论】:

    • 谢谢,这有帮助。这对迁移文件意味着什么?这些应该如何改变?因为在迁移文件中还有has_one :actioncodebelongs_to :organizationt.references 行,它仍然需要组织表中的actioncode_id。
    • 我还想知道,如果您将belongs_to :organization 用于操作代码,那么一个操作代码只能由一个组织使用,而不是许多使用相同操作代码的组织。在 guides.rubyonrails.org/association_basics.html#the-belongs-to-association 我读到“这样声明模型的每个实例都“属于”另一个模型的一个实例。
    • organizations 表将不再具有 actioncode_id 列,因此您需要从中删除该引用,而是每个 Actioncode 将指向 Organizationbelongs_to,因此您需要在 Actioncode 迁移中添加对 :organization 的引用(或创建另一个进行这些更改的迁移)
    • 我在操作码迁移文件中尝试了t.belongs_to :organization, index: true(我尝试了包含和不包含foreign_key: true),并在组织模型文件中尝试了has_one :actioncode。当我尝试播种时,这仍然会产生错误ActiveRecord::AssociationTypeMismatch: Actioncode(#36377580) expected, got Fixnum(#6043080)。所以它似乎仍然期望每个组织都有一个操作代码。
    • 如果要创建一个额外的关联模型,更新中提到的设置是否正确?
    猜你喜欢
    • 2021-12-12
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 2013-02-04
    • 2011-07-21
    • 2017-07-02
    • 1970-01-01
    相关资源
    最近更新 更多