首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >支持多种类型的Ruby On Rails用户模型

问支持多种类型的Ruby On Rails用户模型
EN

Stack Overflow用户
提问于 2010-10-18 12:19:39
回答 2查看 6.1K关注 0票数 10

我正在学习RoR,它来自于多年的c#和MSSQL。

我已经选择了一个项目,为我的兄弟建立一个网站,他是一名租赁物业经理。我认为这应该是相当简单的,因为模型应该是直截了当的,但它认为我可能想得太多了,或者我很难放弃“旧”的方式。无论如何,这是问题所在。我从两个模型(用户模型和属性模型)开始。属性模型很简单,用户就不那么容易了。我认为我们在系统中有三种类型的用户。租户,业主和经理(我的兄弟将是唯一的经理,但我想我会设计它的增长)他管理几个业主的财产,每个人都可以拥有许多财产。每个物业将有一个所有者,一个租户和一个经理。

租户将能够登录并仅看到他们租用的房产,以便填写维护申请或类似的…(在这一点上,甚至没有真正的要求让租户登录到系统,但我认为这将是一个很好的练习)

对于所有者来说也是如此,他们中没有一个人真的需要访问系统(他们雇佣了我的兄弟,这样他们就不必参与其中),但我认为这可能是一个很好的练习。

我使用Nifty_generator生成一个用户,它只给出电子邮件,密码等。我已经按如下…扩展了它

代码语言:javascript
复制
class AddProfileDataToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :first_name, :string
    add_column :users, :last_name, :string
     add_column :users, :address1, :string
     add_column :users, :address2, :string
     add_column :users, :city,:string
     add_column :users, :state, :string
     add_column :users, :zip, :string
     add_column :users, :phone, :string
     add_column :users, :email, :string
     add_column :users, :user_type, integer
  end

  def self.down 
    remove_column :users, :first_name 
    remove_column :users, :last_name
   remove_column :users, :address1
   remove_column :users, :address2
   remove_column :users, :city
   remove_column :users, :state
   remove_column :users, :zip 
   remove_column :users, :phone 
   remove_column :users, :email 
   remove_column :users, :user_type
  end
end

以下是创建Properties表的代码

代码语言:javascript
复制
class CreateProperties < ActiveRecord::Migration
  def self.up
    create_table :properties do |t|
      t.string :address
      t.string :city
      t.string :type
      t.integer :beds
      t.float :baths
      t.float :price
      t.float :deposit
      t.string :terms
      t.string :laundry
      t.datetime :date_available
      t.integer :sqft
      t.integer :owner_id
      t.integer :manager_id
      t.integer :tenant_id
      t.timestamps
    end
  end

  def self.down
    drop_table :properties
  end
end

我将以下代码添加到由nifty_authentication生成器生成的用户模型中

代码语言:javascript
复制
class User < ActiveRecord::Base

  #other stuff in the user model up here......
  validates_length_of :password, :minimum => 4, :allow_blank => true

  #this is the stuff that I have added to the user model
  has_many :managed_properties, :class_name => "Property", :foreign_key => "manager_id"
  has_many :owned_properties, :class_name => "Property", :foreign_key => "owner_id"
  has_one :rented_property, :class_name => "Property", :foreign_key => "tenant_id"

然后我将其添加到属性模型中……

代码语言:javascript
复制
class Property < ActiveRecord::Base
    belongs_to :manager, :class_name => "User" #picked up by the manager_id
    belongs_to :owner, :class_name => "User"  #picked up by the owner_id
    belongs_to :tenant, :class_name => "User"  #picked up by the tenant_id
end

我的问题是,这看起来像是我描述的情况建模的一种可接受的方式吗?

我应该使用单表继承并创建租户模型、经理模型和所有者模型吗?我看到这样做的问题是,一个用户既可以是管理者,也可以是所有者。这可以通过在用户具有多个角色并且角色具有多个用户的情况下具有用户的角色表来解决。我还查看了一个与用户表一对一匹配的配置文件表,并使其具有多态性,但我不认为这种情况真的需要这样做,它也没有解决用户既可以是所有者又是经理的问题……

这就是我开始思考的时候,也许我想得太多了,想出了你在这里看到的东西。

我欢迎您提出任何有建设性的意见。请记住,我从来没有真正在Rails中构建过任何东西,这都是第一次尝试,一周前我甚至还没有在我的计算机上安装rails。

我不知道这是否重要,但我认为管理员/经理将负责创建用户。这将不是一个自助注册类型的网站。经理在签约新的所有者时会添加新的所有者,租户也是如此。这将使确定他正在创建的用户类型变得更容易。

感谢您的任何见解。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-10-18 13:46:15

顺便说一句,这对我来说很好。我可能会使用declarative_authorization来管理您的角色,这最终可能会涉及到一些内容,特别是从UI的角度来看。在这种情况下,管理具有多个角色的用户似乎比STI更合适,因为正如您所说,用户既可以是经理,也可以是租户,等等。

在允许在单个实例中使用所有三个角色的同时,将经理、租户和所有者的代码分开的一种方法可能是基于任何给定用户具有的角色动态地包含表示这些角色的模块。您仍然有一个User基类,但是您可以根据每个用户所拥有的角色混合模块,而不是使用STI,这将限制您使用单一的继承结构,这可能只是在初始化期间根据给定用户的属性belong_to。

为此,我可以创建一个用户工厂,它可以检查用户所扮演的各种角色,并使用相应的模块扩展该用户的singleton class:对于具有租户属性的用户,使用租户模块进行扩展;对于具有托管属性的用户,使用管理器模块进行扩展,等等。

从declarative_authorization的角度来看,您可以根据是否填充了像managed_properties这样的关联来声明role_symbols,例如:

代码语言:javascript
复制
def role_symbols  
  @roles ||= {:manager => :managed_properties, 
    :tenant => :rented_property, 
    :owner => :owned_properties}.map do |k,v|
      k if !send(v).blank?
    end.compact
end

或者类似的东西。您可能希望设置角色并同时包含相应的模块。Ruby和Rails通过metaprogramming techniques为您提供了许多选项,以动态修饰各个模型所需的功能。我的方法可能适合您的应用程序,也可能不适合您的应用程序,但是有无数其他方法可以解决这个问题,并保持代码的干净和干燥。

总的来说,在我看来,您的数据模型是合理的,并且您不使用STI管理多个角色的直觉是正确的。在我看来,你并没有想太多--我认为你走在正确的道路上。对于第一次传递来说,这实际上是相当不错的Rails。

编辑:你知道,我越想,我不确定将管理器/租户/所有者功能放在单独的模块中到底有什么好处。在我以前作为Java/C#人员的化身中,我会一直关注SRP/IOC和关注点的完全分离。但在Ruby和Rails中,这并不是什么大问题,因为它是动态类型的,而且耦合不像在静态类型环境中那样大,或者至少是同样类型的问题。您可能完全可以将所有单独的角色功能放在单用户模型中,而不用担心模块,至少现在还没有。

我在这里持观望态度,并欢迎其他人的意见。对我来说,与Java类/包或.NET类/程序集相比,Ruby类的一个好处是您可以随时根据需要进行重构,而不必担心哪一个类、包、名称空间、dll或jar与另一个类、包、名称空间、dll或jar耦合,等等。但我不再像以前那样偏执了。

编辑: Paul Russell提出了一个很好的观点。我认为你应该认真考虑允许一处房产有多个租户/经理/房东。在Rails中,这可以通过一个关系表和一个has_many来表达:通过关联,再加上用来描述不同类型关系的STI。我还认为有必要颠倒用户(作为租户)和属性之间的关系。一个房产可以有多个租户,但一个租户不能住在多个房产中。(或许他们可以?看起来不太对,但是...)

也许是这样的(这是非常快速和肮脏的,所以请原谅任何遗漏的细节):

代码语言:javascript
复制
class PropertyRole < ActiveRecord::Base
  belongs_to :user
  belongs_to :property
end

class Managership < PropertyRole
  # Manager functionality here
end

class Ownership < PropertyRole
  # Owner functionality here
end

class User < ActiveRecord::Base
  belongs_to :residence, :class_name => 'Property', :foreign_key => 'residence_id'
  has_many :managerships
  has_many :ownerships

  has_many :owned_properties, :through => :ownerships, :classname => 'Property'
  has_many :managed_properties, :through => :managerships, :classname => 'Property'
end

class Property < ActiveRecord::Base
  has_many :tenants, :class_name => 'User', :foreign_key => 'residence_id'
  has_many :managerships
  has_many :ownerships
  has_many :owners, :class_name => 'User', :through => :ownerships
  has_many :managers, :class_name => 'User', :through => :managerships
end

就像我说的,这是快速和肮脏的,高水平的第一次通过。请注意,我们现在已经创建了可以包含Manager和特定于所有者的功能的管理角色和所有权角色,从而消除了以前的两难境地,即是否将这些功能孤立在单独的模块中。

**还请注意,我还颠倒了租户/物业角色--我认为这是对您的域的必要更改。显然,一个住宅可以有多个租户。在我看来(目前),您可以在用户模型上保留特定于租户的功能。

票数 8
EN

Stack Overflow用户

发布于 2010-10-18 13:59:38

让我印象深刻的是,你目前的模型禁止在给定的房产中有多个租户或房东,并假设这些关系是永久的。

至少在英国,一对夫妇拥有一套房产的情况很常见,因此可能会有多个房东(例如,我和我的妻子就是这种情况)。同样,对于某些类型的出租,在一处房产上有多个租户是很常见的。

如果你认为我是对的,那么值得考虑在用户和属性之间引入一个'user_property_role‘模型对象。然后,您就拥有了从用户和属性到user_property_role的has_many关系。如果此角色有一个'relationship type‘字段,您可以将其设置为'landlord',然后您可以使用has_many :through和命名作用域(在user_property_role上)对象来执行property.users.landlords或property.users.tenants等操作。

采用这种方法还可以让你做一些事情,比如给出这些关系的“开始”和“结束”日期,例如,记录一个房产随着时间的推移有多个租户的事实,或者随着时间的推移,一个房产可能由不同的人管理。同样,您应该能够将其构建到一组命名作用域中,这样您就可以执行例如property.users.current.tenants甚至user.properties.current.tenants。

希望这会有帮助,不会只会增加你的困惑!

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3956588

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档