具有 AR 枚举范围的 HABTM
HABTM with AR enum scope
如何让模型与同一模型的记录子集相关联,由 AR 枚举范围定义?
我认为像下面这样的东西会起作用,但它不起作用。如果 has_many :through
可以简化事情,我愿意使用它,但现在看来有点矫枉过正。
class User < ActiveRecord::Base
enum role: [:doctor, :patient, :clinician]
has_and_belongs_to_many :doctors, &:doctor?, class_name: "User"
end
更正建议的版本会出现语法错误;
class User < ActiveRecord::Base
enum role: [:doctor, :patient, :clinician]
has_and_belongs_to_many :doctors, &:doctor, class_name: "User"
end
错误:
SyntaxError: ~/m2/app/models/user.rb:3: syntax error, unexpected ',', expecting keyword_end
has_and_belongs_to_many :doctors, &:doctor, class_name: "User"
^
使用 ->{doctor}
语法可以,但我想知道为什么 &
语法是错误的。
好的,请看下面为什么 &
语法是错误的,显然 :doctor.to_proc 技巧不起作用,因为 to_proc 将当前对象绑定到 proc 而它应该是传递给 proc,这意味着 ->{}
或 Proc.new{}
在这种情况下确实是必需的。
问题是 scope
过程是在 class 上下文中计算的(好吧,从技术上讲,关系上下文从您的模型继承了 class 方法)。例如,来自 docs for has_and_belongs_to_many
:
has_and_belongs_to_many :projects, -> { includes :milestones, :manager }
使用此代码,调用 SomeModel.projects
将等同于调用 SomeModel.projects.includes(:milestones, :manager)
。现在,这是您的代码:
has_and_belongs_to_many :doctors, &:doctor?, class_name: "User"
使用这段代码,调用 User.doctors
将等同于调用 User.doctors.doctor?
,这是行不通的,因为 doctor?
是 User 上的实例方法,而不是 class方法。
对于解决方案,我们只需要检查docs for enum
。在底部有这个例子:
In rare circumstances you might need to access the mapping directly. The mappings are exposed through a class method with the pluralized attribute name:
Conversation.statuses # => { "active" => 0, "archived" => 1 }
Use that class method when you need to know the ordinal value of an enum:
Conversation.where("status <> ?", Conversation.statuses[:archived])
Where conditions on an enum attribute must use the ordinal value of an enum.
因为 Rails 自动为枚举创建范围,例如User.doctor
,我们其实可以做得更好:
has_and_belongs_to_many :doctors, ->{ doctor }, class_name: "User"
您可能想尝试将其缩短为以下内容:
has_and_belongs_to_many :doctors, &:doctor, class_name: "User"
...但是正如您已经发现的那样,这会给您一个 SyntaxError。原因是 &
运算符告诉 Ruby 将给定对象转换为块并将其用作方法的块参数。如果对象不是 proc(如 :doctor
),则首先调用其 to_proc
方法,这就是为什么例如[1,2].reduce(&:+)
有效。但是该块必须始终是最后一个参数(并且只能有一个),因此当您在 &:doctor
.
之后放置另一个参数时会出现语法错误
但是,您可以这样做:
has_and_belongs_to_many :doctors, :doctor.to_proc,
class_name: "User"
...但我不认为你真的从中得到了什么。
如何让模型与同一模型的记录子集相关联,由 AR 枚举范围定义?
我认为像下面这样的东西会起作用,但它不起作用。如果 has_many :through
可以简化事情,我愿意使用它,但现在看来有点矫枉过正。
class User < ActiveRecord::Base
enum role: [:doctor, :patient, :clinician]
has_and_belongs_to_many :doctors, &:doctor?, class_name: "User"
end
更正建议的版本会出现语法错误;
class User < ActiveRecord::Base
enum role: [:doctor, :patient, :clinician]
has_and_belongs_to_many :doctors, &:doctor, class_name: "User"
end
错误:
SyntaxError: ~/m2/app/models/user.rb:3: syntax error, unexpected ',', expecting keyword_end
has_and_belongs_to_many :doctors, &:doctor, class_name: "User"
^
使用 ->{doctor}
语法可以,但我想知道为什么 &
语法是错误的。
好的,请看下面为什么 &
语法是错误的,显然 :doctor.to_proc 技巧不起作用,因为 to_proc 将当前对象绑定到 proc 而它应该是传递给 proc,这意味着 ->{}
或 Proc.new{}
在这种情况下确实是必需的。
问题是 scope
过程是在 class 上下文中计算的(好吧,从技术上讲,关系上下文从您的模型继承了 class 方法)。例如,来自 docs for has_and_belongs_to_many
:
has_and_belongs_to_many :projects, -> { includes :milestones, :manager }
使用此代码,调用 SomeModel.projects
将等同于调用 SomeModel.projects.includes(:milestones, :manager)
。现在,这是您的代码:
has_and_belongs_to_many :doctors, &:doctor?, class_name: "User"
使用这段代码,调用 User.doctors
将等同于调用 User.doctors.doctor?
,这是行不通的,因为 doctor?
是 User 上的实例方法,而不是 class方法。
对于解决方案,我们只需要检查docs for enum
。在底部有这个例子:
In rare circumstances you might need to access the mapping directly. The mappings are exposed through a class method with the pluralized attribute name:
Conversation.statuses # => { "active" => 0, "archived" => 1 }
Use that class method when you need to know the ordinal value of an enum:
Conversation.where("status <> ?", Conversation.statuses[:archived])
Where conditions on an enum attribute must use the ordinal value of an enum.
因为 Rails 自动为枚举创建范围,例如User.doctor
,我们其实可以做得更好:
has_and_belongs_to_many :doctors, ->{ doctor }, class_name: "User"
您可能想尝试将其缩短为以下内容:
has_and_belongs_to_many :doctors, &:doctor, class_name: "User"
...但是正如您已经发现的那样,这会给您一个 SyntaxError。原因是 &
运算符告诉 Ruby 将给定对象转换为块并将其用作方法的块参数。如果对象不是 proc(如 :doctor
),则首先调用其 to_proc
方法,这就是为什么例如[1,2].reduce(&:+)
有效。但是该块必须始终是最后一个参数(并且只能有一个),因此当您在 &:doctor
.
但是,您可以这样做:
has_and_belongs_to_many :doctors, :doctor.to_proc,
class_name: "User"
...但我不认为你真的从中得到了什么。