代码之家  ›  专栏  ›  技术社区  ›  Umair Abid

如何在rails中基于列值创建动态关系

  •  0
  • Umair Abid  · 技术社区  · 5 年前

    我有一个简单的例子,但不知道如何使用 ActiveRecord . 所以我有一个类用户,可以有一个 profile role 它是一个枚举。看起来像这样

    class User < ActiveRecord::Base
        enum role: { manager: 1, writer: 2 }
    
        has_one :profile
    end
    

    我也有 Writer Manager belongs_to 用户

    class Manager < ActiveRecord::Base
        belongs_to :user
    end
    
    class Writer < ActiveRecord::Base
        belongs_to :user
    end
    

    轮廓

    任何帮助都会得到安抚

    0 回复  |  直到 5 年前
        1
  •  1
  •   Jay-Ar Polidario    5 年前

    日间;夜间:

    has_many 使用动态“表名”(也称为动态模型),主要是因为没有动态等效的SQL字符串来表示,如下所示:

    # Let's pretend that you have a `Post` model `belongs_to :user` and has an attribute `is_enabled:boolean`
    # and that `User` `has_one :post`...
    
    User.joins(:post).where(posts: { is_enabled: true })
    # would generate an SQL
    # User Load (0.6ms) SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE "posts"."is_enabled" = true LIMIT 1
    
    # ^ This works fine because `has_one :posts` always is mapped to the `posts` table
    # but since you are asking for a dynamic one, then see an equivalent below
    
    User.joins(:profile).where(":managers or :writers": { is_enabled: true })
    # User Load (0.6ms) SELECT "users".* FROM "users" INNER JOIN "what_table" on "what_table"."user_id" = "users"."id" WHERE "what_table"."is_enabled" = true LIMIT 1
    # ^ which as you could see does not have an exact SQL equivalent because it is
    # "trying to" INNER JOIN on a "dynamic" table. You can do this per `User` record,
    # because you know what to INNER JOIN with, but for a collection of `User` records,
    # there is no such SQL "dynamic-table-name-matching" equivalent.
    

    class User < ActiveRecord::Base
      enum role: { manager: 1, writer: 2 }
    
      has_one :manager
      has_one :writer
    
      def profile
        case role
        when 'manager' then manager
        when 'writer' then writer
        else raise NotImplementedError
        end
      end
    
      # or if you prefer a dynamic-matching one:
      # def profile
      #   send(role.to_sym)
      # end
    end
    

    使用示例

    # rails console
    user = User.first
    puts user.profile
    # => returns either <Manager...>, <Writer...>, or nil
    

    但警告是上述定义的替代解决方案 profile 作为一个 而不是 协会 ,因此您将失去执行 INNER JOIN