Rails:坏联想? [has_many , through] 如何测试是否正常?
Rails: Bad Associations? [has_many , through] How to test if working?
我正在努力解决数据模型中的问题。我有以下型号:
class User < ActiveRecord::Base
...
has_many :claims #user-claims
has_many :claims, through: :rulings, as: :commissars
...
end
class Claim < ActiveRecord::Base
...
belongs_to :user
has_many :users, through: :rulings, as: :commissars
...
end
class Ruling < ActiveRecord::Base
belongs_to :user
belongs_to :claim
end
错误:
undefined method `commissars' for #<Claim:0xc5ac090>
模型说明:
用户可以撰写声明(一个声明属于一个用户),用户可以扮演委员的角色来裁决声明(每个声明的最大委员数 = 3)。
有什么方法可以解决这个问题或改善关系吗?
首先,我建议您返回并仔细阅读 Guide,因为我相信您从根本上误解了很多事情。例如,as:
选项并不表示角色,而是表示多态连接的存在。此外,您不能在同一模型上声明两次 has_many :claims
。不管怎样,再去读一遍。
但是,对于您的问题 - 一个功能性但有点不雅的方法可能看起来像:
class User < ActiveRecord::Base
...
has_many :claims
has_many :claim_commissars, foreign_key: "commissar_id"
has_many :commissar_claims, through: :claim_commissars, class_name: "Claim"
# ^^^^^^^^^^^^^^^^^^^^^
# this bit may be wrong
...
end
class Claim < ActiveRecord::Base
...
belongs_to :user
has_one :ruling
has_many :claim_commissars
has_many :commissars, through: :claim_commissars
...
end
class ClaimCommissar < ActiveRecord::Base
...
belongs_to :claim
belongs_to :commissar, class_name: "User"
...
end
class Ruling < ActiveRecord::Base
...
belongs_to :claim
belongs_to :commissar, class_name: "User"
...
end
您需要在代码中强制执行“最多 3 个委员”。
这还没有经过测试,您可能需要 fiddle 才能使用它。但是,希望它能让你朝着更好的方向前进。
祝你好运!
这个领域模型需要一些非常复杂的关系,所以第一次尝试没有得到它并不丢人。
让我们从用户和声明开始:
class User < ActiveRecord::Base
has_many :claims, foreign_key: 'claimant_id',
inverse_of: :claimant
end
class Claim < ActiveRecord::Base
belongs_to :claimant, class_name: 'User',
inverse_of: :claims
end
这是一个非常基本的一对多关系,但有所不同。由于 User 将与 Claim 有一堆关系,我们将关系称为默认值 user
以外的其他名称,以便定义关系的性质。
class_name: 'User'
选项告诉 ActiveRecord 加载 class 用户并使用它来确定要查询的 table 以及 class 到 [=59= 的内容] 结果如。每当 class 名称不能直接从协会名称派生时就需要它。由于 Rails 延迟解析 class 依赖项的方式,该选项应该是一个字符串而不是常量。
现在让我们添加政委角色。我们将使用 ruling
作为联接 table:
class Ruling < ActiveRecord::Base
belongs_to :claim
belongs_to :commissioner, class_name: 'User'
end
请注意,这里我们有一个与 User 的关系,为清楚起见,我们将其称为 commissioner
。现在我们将关系添加到 Claim
:
class Claim < ActiveRecord::Base
belongs_to :claimant, class_name: 'User',
inverse_of: :claims
has_many :rulings
has_many :commissioners, through: :rulings
end
然后我们需要在用户端设置关系:
class User < ActiveRecord::Base
has_many :claims, foreign_key: 'claimant_id',
inverse_of: :claimant
# rulings as claimant
has_many :rulings, through: :claims
has_many :rulings_as_commissioner, class_name: 'Ruling',
foreign_key: 'commissioner_id'
has_many :claims_as_commissioner, through: :rulings_as_commissioner,
source: :claim
end
请注意 source: :claim
选项,我们告诉 ActiveRecord 我们希望加入哪一方 table。
当然,要使其正常工作,我们需要正确设置列和外键。这些迁移是为了从头开始创建 tables,但您可以轻松地重写它们以改变现有的 tables:
class CreateClaims < ActiveRecord::Migration
def change
create_table :claims do |t|
t.belongs_to :claimant, index: true, foreign_key: false
t.timestamps null: false
end
# we need to setup the fkey ourself since it is not conventional
add_foreign_key :claims, :users, column: :claimant_id
end
end
class CreateRulings < ActiveRecord::Migration
def change
create_table :rulings do |t|
t.belongs_to :claim, index: true, foreign_key: true
t.belongs_to :commissioner, index: true, foreign_key: false
t.timestamps null: false
end
add_foreign_key :rulings, :users, column: :commissioner_id
add_index :rulings, [:claim_id, :commissioner_id], unique: true
end
end
max numbers of commissars = 3 per claim
这实际上并不是关联的一部分,您可以通过添加验证或关联回调来强制执行此规则。
class Ruling < ActiveRecord::Base
# ...
validate :only_three_rulings_per_claim
private
def only_three_rulings_per_claim
if claim.rulings.size >= 3
errors.add(:claim, "already has the max number of commissars")
end
end
end
参见:
我正在努力解决数据模型中的问题。我有以下型号:
class User < ActiveRecord::Base
...
has_many :claims #user-claims
has_many :claims, through: :rulings, as: :commissars
...
end
class Claim < ActiveRecord::Base
...
belongs_to :user
has_many :users, through: :rulings, as: :commissars
...
end
class Ruling < ActiveRecord::Base
belongs_to :user
belongs_to :claim
end
错误:
undefined method `commissars' for #<Claim:0xc5ac090>
模型说明:
用户可以撰写声明(一个声明属于一个用户),用户可以扮演委员的角色来裁决声明(每个声明的最大委员数 = 3)。
有什么方法可以解决这个问题或改善关系吗?
首先,我建议您返回并仔细阅读 Guide,因为我相信您从根本上误解了很多事情。例如,as:
选项并不表示角色,而是表示多态连接的存在。此外,您不能在同一模型上声明两次 has_many :claims
。不管怎样,再去读一遍。
但是,对于您的问题 - 一个功能性但有点不雅的方法可能看起来像:
class User < ActiveRecord::Base
...
has_many :claims
has_many :claim_commissars, foreign_key: "commissar_id"
has_many :commissar_claims, through: :claim_commissars, class_name: "Claim"
# ^^^^^^^^^^^^^^^^^^^^^
# this bit may be wrong
...
end
class Claim < ActiveRecord::Base
...
belongs_to :user
has_one :ruling
has_many :claim_commissars
has_many :commissars, through: :claim_commissars
...
end
class ClaimCommissar < ActiveRecord::Base
...
belongs_to :claim
belongs_to :commissar, class_name: "User"
...
end
class Ruling < ActiveRecord::Base
...
belongs_to :claim
belongs_to :commissar, class_name: "User"
...
end
您需要在代码中强制执行“最多 3 个委员”。
这还没有经过测试,您可能需要 fiddle 才能使用它。但是,希望它能让你朝着更好的方向前进。
祝你好运!
这个领域模型需要一些非常复杂的关系,所以第一次尝试没有得到它并不丢人。
让我们从用户和声明开始:
class User < ActiveRecord::Base
has_many :claims, foreign_key: 'claimant_id',
inverse_of: :claimant
end
class Claim < ActiveRecord::Base
belongs_to :claimant, class_name: 'User',
inverse_of: :claims
end
这是一个非常基本的一对多关系,但有所不同。由于 User 将与 Claim 有一堆关系,我们将关系称为默认值 user
以外的其他名称,以便定义关系的性质。
class_name: 'User'
选项告诉 ActiveRecord 加载 class 用户并使用它来确定要查询的 table 以及 class 到 [=59= 的内容] 结果如。每当 class 名称不能直接从协会名称派生时就需要它。由于 Rails 延迟解析 class 依赖项的方式,该选项应该是一个字符串而不是常量。
现在让我们添加政委角色。我们将使用 ruling
作为联接 table:
class Ruling < ActiveRecord::Base
belongs_to :claim
belongs_to :commissioner, class_name: 'User'
end
请注意,这里我们有一个与 User 的关系,为清楚起见,我们将其称为 commissioner
。现在我们将关系添加到 Claim
:
class Claim < ActiveRecord::Base
belongs_to :claimant, class_name: 'User',
inverse_of: :claims
has_many :rulings
has_many :commissioners, through: :rulings
end
然后我们需要在用户端设置关系:
class User < ActiveRecord::Base
has_many :claims, foreign_key: 'claimant_id',
inverse_of: :claimant
# rulings as claimant
has_many :rulings, through: :claims
has_many :rulings_as_commissioner, class_name: 'Ruling',
foreign_key: 'commissioner_id'
has_many :claims_as_commissioner, through: :rulings_as_commissioner,
source: :claim
end
请注意 source: :claim
选项,我们告诉 ActiveRecord 我们希望加入哪一方 table。
当然,要使其正常工作,我们需要正确设置列和外键。这些迁移是为了从头开始创建 tables,但您可以轻松地重写它们以改变现有的 tables:
class CreateClaims < ActiveRecord::Migration
def change
create_table :claims do |t|
t.belongs_to :claimant, index: true, foreign_key: false
t.timestamps null: false
end
# we need to setup the fkey ourself since it is not conventional
add_foreign_key :claims, :users, column: :claimant_id
end
end
class CreateRulings < ActiveRecord::Migration
def change
create_table :rulings do |t|
t.belongs_to :claim, index: true, foreign_key: true
t.belongs_to :commissioner, index: true, foreign_key: false
t.timestamps null: false
end
add_foreign_key :rulings, :users, column: :commissioner_id
add_index :rulings, [:claim_id, :commissioner_id], unique: true
end
end
max numbers of commissars = 3 per claim
这实际上并不是关联的一部分,您可以通过添加验证或关联回调来强制执行此规则。
class Ruling < ActiveRecord::Base
# ...
validate :only_three_rulings_per_claim
private
def only_three_rulings_per_claim
if claim.rulings.size >= 3
errors.add(:claim, "already has the max number of commissars")
end
end
end
参见: