多种类型的Ruby On Rails用户模型 [英] Ruby On Rails User Model for multiple types

查看:57
本文介绍了多种类型的Ruby On Rails用户模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习来自多年的c#和MSSQL的RoR.

I am learning RoR coming from many years of c# and MSSQL.

我选择了一个项目来为我的哥哥(一个出租物业经理)建立一个网站.我认为这应该很容易,因为模型应该简单明了,但是它认为我可能考虑得太多了,或者我无法摆脱旧的"方式.无论如何,这就是问题所在.我从两个模型(User和Property)开始.属性模型很简单,用户就不那么多了.我认为系统中有三种类型的用户.租户,所有者和管理者(我的兄弟将是唯一的管理者,但我认为我会设计它来发展).他为多个所有者管理财产,每个所有者可以拥有许多财产.每个物业将有一名所有者,一名租户和一名管理人员.

I have picked a project to build a web site for my brother who is a rental property manager. I figured this should be fairly easy as the models should be straight forward, but it think I may be over thinking everything or I’m having trouble letting go of the ‘old’ way. Anyway here is the problem. I am starting off with just two models (User and Property) . The property model is easy, the user not so much. I figured that we have three types of users in the system. Tenants, Owners and Managers (my brother will be the only manager but I figured I would design it to grow) He manages properties for several owners each of whom can own many properties. Each property will have one owner, one tenant and one manger.

租户将能够登录并看到他们租用的物业,以填写维护要求或类似的内容……(目前甚至没有真正的要求,甚至可以让租户登录系统,但我认为这样做会做个好运动)

Tenants will be able to log in and just see the property they rent to maybe fill out a maintenance request or something like that…(no real requirement at this point to even give tenant a login to the system but I thought it would be a good exercise)

所有者也有同样的想法,他们中的任何一个都不真正需要访问系统(他们雇用了我的兄弟,因此他们不必参与其中),但我认为这可能是不错的选择,而且还是不错的练习.

Same thing goes for owners, none of them really need access to the system (they hire my brother so they don’t have to be involved) but I thought it might be nice and again a good exercise.

我使用Nifty_generator生成了一个用户,该用户仅提供电子邮件,密码等.我对其进行了如下扩展...

I used the Nifty_generator to generate a user, which just gives email, password etc. I have extended it as follows…

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

这是创建属性表的代码

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生成器生成的用户模型中添加了以下内容

I added the following to the user model that was generated by the nifty_authentication generator

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"

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

I then added this to the property model....

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

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

My question is, does this look like an acceptable way of modeling the situation I described?

我应该使用单表继承并创建租户模型吗?经理模式;和所有者模型?我这样做的问题是,单个用户既可以是管理员,也可以是所有者.然后可以通过为用户提供一个角色表来解决此问题,其中一个用户具有多个角色,而一个角色具有多个用户.我还查看了一个与用户表一对一匹配的配置文件表,并使其具有多态性,但我不认为这种情况确实需要这样做,也无法解决用户可以成为所有者的问题还有一个经理.....

Should I be using the single table inheritance and creating a tenant model; a manager model; and an owner model? The problem I saw with doing that was that a single user could be both a manager and an owner. This could be solved by then having a roles tables for the user where a user has many roles and a role has many users. I had also looked at a profile table with a one to one match with the user table and making this polymorphic but I didn't think that this situation really calls for that and it didn't solve the issue where a user can be an owner and a manager.....

这是当我开始认为也许我正在考虑问题并提出您在这里看到的内容时.

This is when I started to think that maybe I was over thinking the problem and came up with what you see here.

我欢迎您提出任何建设性意见.请记住,我从未真正在Rails中构建任何东西,这是第一次尝试,一个星期前,我什至从未在计算机上安装过Rails.

I welcome any constructive comments you may have. Please keep in mind that I have never actually built anything in Rails and this is all a first attempt, one week ago I had never even installed rails on my computer.

我不知道这是否重要,但我认为管理员/经理将负责创建用户.这将不是网站的自助注册类型.经理在注册新所有者时将添加新所有者,租户也将添加新所有者.这样可以更轻松地确定他正在创建的用户类型.

I don't know if this matters but I figured that the admin / manager would be responsible for creating users. This will not be a self sign up type of site. The manager will add new owners when he signs up new owner, and the same will go for tenants. This will make it easier to determine the type of user he is creating.

感谢您的任何见识.

推荐答案

FWIW,对我来说,这很好.我可能会查看 declarative_authorization 来管理您的角色,这最终可能会涉及到某些方面,尤其是从UI角度来看.在这种情况下,管理具有多个角色的用户似乎比STI更合适,因为正如您所说,用户既可以是管理员又可以是租户,等等.

FWIW, this looks fine to me. I might look at declarative_authorization to manage your roles, which might end up somewhat involved, particularly from the UI standpoint. Managing users with multiple roles seems more appropriate than STI in this situation, because, as you say, a user can be both manager and tenant, etc.

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

One approach to keeping the code for manager, tenant and owner separate, while allowing for the use of all three roles in a single instance, might be to dynamically include modules representing those roles based on what roles any given user has. You'd still have a base class of User, but instead of using STI, which would limit you to a single inheritance structure, you could mix in modules based on the roles each user has, which might simply pivot on what Properties belong_to a given user during initialization.

为此,我可以创建一个用户工厂,该工厂可以检查用户所扮演的各种角色,并扩展

For this I might create a User factory that can inspect the user for the various roles it plays and extend the singleton class of that user with the corresponding module: extend with the Tenant module for users that have tenant properties, extend with the Manager module for users that have managed properties, etc.

从declarative_authorization的角度来看,您可以类似地基于是否填充了诸如managed_properties之类的关联来声明role_symbols,例如:

From the standpoint of declarative_authorization, you could declare the role_symbols similarly based on whether associations like managed_properties were populated, for instance:

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通过元编程技术为您提供了许多选择,以动态修饰各个模型所需的功能.我的方法可能适合您的应用程序,也可能不适合您的应用程序,但是有无数其他方法可以解决该问题并使代码保持干净和DRY.

Or something similar. You'd probably want to set the roles AND include the corresponding module at the same time. Ruby and Rails gives you many options via metaprogramming techniques to dynamically decorate with the functionality individual models need. My approach may or may not be appropriate for your application, but there are countless other ways you could approach the problem and keep your code clean and DRY.

总的来说,在我看来,您的数据模型是正确的,并且您本能不使用STI管理多个角色是正确的.在我看来,您似乎并没有想得太深-我认为您的方向正确.第一次通过实际上很漂亮.

Overall it seems to me your data model is sound, and your instinct not to use STI to manage multiple roles is correct. It doesn't look to me like you've overthought it -- I think you're on the right track. It's actually pretty Rails-y for a first pass.

您知道的越多,我就不确定将管理器/租户/所有者功能保留在单独模块中的好处是什么.在我以前作为Java/C#角色的化身时,我本来会想到 SRP /IOC 和关注点完全分开.但是在Ruby和Rails中,这并不是一件大事,因为它是动态类型的,而耦合在静态类型的环境中也没有那么大,或者至少是同一种类型.您可以将所有单个角色功能都放在单个用户模型中,而不必担心模块,至少现在还不用担心.

You know, the more I think about it, I'm not sure what the benefit of keeping the manager/tenant/owner functionality in separate modules really is. In my former incarnation as a Java/C# guy I would have been all about the SRP/IOC and total separation of concerns. But in Ruby and Rails it's not nearly as big of a deal, since it's dynamically typed and coupling is not nearly as big, or at least the same sort, of concern that it is in statically-typed environments. You might be perfectly fine just putting all of the individual role functionality in the single User model and not worry with the modules, at least not yet.

我在这里碰壁,欢迎其他人的意见.对我来说,与Java类/包或.NET类/程序集相比,Ruby类的好处之一是您可以始终根据需要进行重构,而不必担心哪个类,程序包,名称空间,dll或jar是什么.耦合到另一个,等等.我并不是说SRP在Ruby中并不重要,一点也不.但是我对此并不像以前那样偏执.

I'm on the fence here, and would welcome input from others. To me one of the benefits to Ruby classes, as opposed to Java classes/packages or .NET classes/assemblies, is that you can always refactor as needed and not be nearly as concerned about which class, package, namespace, dll or jar is coupled to another, etc. I'm not saying SRP isn't important in Ruby, not at all. But I'm not nearly as paranoid about it as I used to be.

保罗·罗素(Paul Russell)提出了一个很好的观点.我认为您应该认真考虑允许每个属性允许多个租户/经理/房东.在Rails中,这可以通过关系表和has_many:through关联以及STI来描述不同类型的关系来表示.我也认为有必要颠倒用户(作为租户)和财产之间的关系.一个物业可以有多个租户,但是一个租户不能住在一个以上的物业. (或者也许他们可以?似乎不正确,但是...)

Paul Russell makes an excellent point. I think you should seriously consider allowing multiple tenants/managers/landlords per property. In Rails this could be expressed through a relational table and a has_many :through association, plus STI to describe the different types of relationships. I also think it will be necessary to invert the relationship between User (as Tenant) and Property. A Property can have more than one Tenant, but a Tenant can't live at more than one property. (or maybe they can? Doesn't seem right, but...)

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

Maybe something like (this is very quick and dirty, so forgive any missed details please):

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

就像我说的那样,这是又快又脏的,是高级的第一遍.请注意,我们现在已经创建了Managership和Ownership角色,它们可以包含Manager和Owner特定的功能,从而消除了以前是否需要在单独的模块中单独使用该功能的难题.

Like I said, this is quick and dirty, a high-level first pass. Note that we've now created Managership and Ownership roles that can contain Manager and Owner-specific functionality, eliminating the former dilemma as to whether to silo that functionality in separate modules.

**还请注意,我也改变了承租人/财产"角色-我认为这是对您的域的必要更改.显然,一个住所可以有多个租户.在我看来(目前),您可以在User模型上保留特定于租户的功能.

** Note also that I've inverted the Tenant/Property role as well -- I think this was a necessary change to your domain. Obviously a residence can have more than one tenant. It seems to me (at the moment) that you can keep the tenant-specific functionality on the User model.

这篇关于多种类型的Ruby On Rails用户模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆