【问题标题】:HABTM with AR enum scope具有 AR 枚举范围的 HABTM
【发布时间】:2015-07-28 21:47:37
【问题描述】:

如何让模型与来自同一模型的记录子集关联,由 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"
                                             ^

使用-&gt;{doctor} 语法有效,但我想知道为什么&amp; 语法错误。

好的,看看下面为什么&amp; 语法是错误的,显然 :doctor.to_proc 技巧不起作用,因为 to_proc 将当前对象绑定到 proc 而它应该被传递给 proc,这意味着 @在这种情况下,987654328@ 或 Proc.new{} 确实是必要的。

【问题讨论】:

    标签: ruby-on-rails activerecord enums associations


    【解决方案1】:

    问题在于scope proc 是在类上下文中评估的(从技术上讲,是关系上下文,它从您的模型继承类方法)。比如来自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 上的实例方法,而不是类方法。

    对于解决方案,我们只需要检查docs for enum。在底部有这个例子:

    在极少数情况下,您可能需要直接访问映射。映射通过具有复数属性名称的类方法公开:

    Conversation.statuses # => { "active" => 0, "archived" => 1 }
    

    当您需要知道枚举的序数值时,使用该类方法:

    Conversation.where("status <> ?", Conversation.statuses[:archived])
    

    枚举属性的条件必须使用枚举的序数值。

    因为 Rails 会自动为枚举创建范围,例如User.doctor,其实我们可以做得更好:

    has_and_belongs_to_many :doctors, ->{ doctor }, class_name: "User"
    

    您可能想尝试将其缩短为以下内容:

    has_and_belongs_to_many :doctors, &:doctor, class_name: "User"
    

    ...但是正如您已经发现的那样,这会给您一个 SyntaxError。原因是 &amp; 运算符告诉 Ruby 将给定对象转换为块并将其用作方法的块参数。如果对象不是 proc(如 :doctor),则首先调用其 to_proc 方法,这就是为什么例如[1,2].reduce(&amp;:+) 有效。但是该块必须始终是最后一个参数(并且只能有一个),因此当您在 &amp;:doctor 之后放置另一个参数时会出现语法错误。

    但是,您可以这样做:

    has_and_belongs_to_many :doctors, :doctor.to_proc,
                            class_name: "User"
    

    ...但我不认为你真的从中得到什么。

    【讨论】:

    • 您对doctor? 和doctor 之间的区别是正确的,但请您谈谈为什么&符号语法在实践中不起作用?
    • 抱歉,不清楚。我已经编辑了答案的最后一部分来解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-06
    相关资源
    最近更新 更多