为用户添加多个配置文件类型

时间:2016-01-22 07:37:21

标签: ruby-on-rails single-table-inheritance sti profiles

我正在设计一个用户登录并创建个人资料的rails应用程序。 我希望用户可以选择3种配置文件类型(提供商,搜索者,专业人士)。

我使用了devise gem进行用户身份验证。 我有个人资料模型,必须遵循协会。

User.rb has_one:个人资料

Profile.rb belongs_to:user

目前,用户可以创建通用配置文件,但我希望对其进行更改,以便每个配置文件类型都有不同的输入字段。

最基本的方法是什么?

2 个答案:

答案 0 :(得分:0)

你可以使用STI(单表继承)但我通常会避免它 - 你必须问自己的问题是:"我真的需要为每种配置文件类型定义一个新模型吗?"

实现此目的的最简单方法之一是只设置kind属性,然后为每个Profile#kind(您不能使用为STI保留的类型关键字)自己的关联:

class User
  has_many :profiles
  has_one :provider_profile, -> {where(kind: "provider")}, class_name: "Profile"
  has_one :seeker_profile, -> {where(kind: "seeker")},  class_name: "Profile"
  has_one :professional_profile, -> {where(kind: "professional")},  class_name: "Profile"

end

答案 1 :(得分:0)

STI所需的另一个选项是enum

#app/models/profile.rb
class Profile < ActiveRecord::Base
   enum state: [:provider, :seeker, :professional]
end

这会为您提供int列(在本例中为state),表示对象是否具有特定属性(EG provider? / seeker?等)。

它会为STI提供一组类似的功能,除了给你一个模型来调用(而不是你使用STI模式时得到的3。)

STI

如果你有需要来调用多个模型,那么STI是好的

大多数时候,你没有。有一个good writeup about it here.

如果在案件中使用STI,您最终会得到:

#app/models/profile.rb
class Profile < ActiveRecord::Base
   belongs_to :user
end

#app/models/seeker.rb
class Seeker < Profile
end

#app/models/professional.rb
class Professional < Profile
   def add_client
      ...
   end
end

需要注意的重要一点是,虽然这在您的模型中看起来很漂亮,但这意味着您的前端需要调用:

#config/routes.rb
resources :professionals, only: [:new, :create]

#app/controllers/professionals_controller.rb
class ProfessionalsController < ApplicationController
   def index
      @professional = Professional.find params[:id]
   end
end

如果您打算致电Profile.find_by type: "professional",请忘掉它。那是antipattern&amp;非常低效。

-

确定您是否真的需要遵循STI模式的方法非常简单 - 每个subclass需要额外的方法/属性吗?

如果没有,那么你就可以使用枚举:

#app/models/user.rb
class User < ActiveRecord::Base
   has_one :profile
   before_create :build_profile #-> creates blank profile with each new user
   accepts_nested_attributes_for :profile
end

#app/models/profile.rb
class Profile < ActiveRecord::Base
   belongs_to :user
   enum state: [:provider, :seeker, :professional] #-> defaults to "provider"
end

我个人会在控制器中使用enum条件:

#app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
   def edit
      @profile = current_user.profile
      if @profile.professional?
        ...
      elsif @profile.seeker?
        ...
      end
   end
end

-

了解其工作原理的最佳方法是查看object orientated programming,简而言之就是Ruby / Rails。

OOP使用来创建"objects" ...

enter image description here

这些对象中的每一个都被调用为实例(这是术语“实例变量”和“实例方法”的来源) - 这些实例由应用程序保存在内存中。

OOP程序的工作方式是从用户那里获取输入,确定对象之间的交互并输出结果。这就是所有现代游戏的运作方式。

因此,当您查看Rails时,您必须从您将要调用的对象的角度来看待它。你真的想要拉Professional个对象吗,还是只是你正在使用的Profile