STI 的另一个选项是enum:
#app/models/profile.rb
class Profile < ActiveRecord::Base
enum state: [:provider, :seeker, :professional]
end
这为您提供了一个 int 列(在本例中为 state),它表示对象是否具有特定属性(例如 provider? / seeker? 等)。
它将提供与STI 类似的一组功能,除了为您提供一个可供调用的模型(而不是使用 STI 模式时您会得到的3)。
性传播感染
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,效率很低。
--
判断你是否真的需要遵循 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"...
这些对象中的每一个都作为 instances 调用(这是术语“实例变量”和“实例方法”的来源) - 这些实例由您的应用程序保存在内存中。
OOP 程序的工作方式是接受用户的输入,确定对象之间的交互,然后输出结果。这就是所有现代游戏的运作方式。
因此,当您查看 Rails 时,您必须从您将要调用的 对象 的角度来看待它。你真的想拉Professional 对象,还是只是你正在使用的Profile?