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

问题描述

我正在从多年的 c# 和 MSSQL 中学习 RoR.

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

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

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.

感谢您提供的任何见解.

Thanks for any insight you may have.

推荐答案

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.

为此,我可能会创建一个用户工厂,它可以检查用户扮演的各种角色并扩展 具有相应模块的用户的单例类:为具有租户属性的用户使用 Tenant 模块扩展,为具有托管属性的用户使用 Manager 模块扩展等.

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

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 来管理多个角色的直觉是正确的.在我看来,你并没有想太多——我认为你走在正确的轨道上.第一次通过时,它实际上是非常棒的 Rails-y.

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

就像我说的,这是快速而肮脏的,高级别的第一关.请注意,我们现在已经创建了管理和所有权角色,它们可以包含特定于经理和所有者的功能,从而消除了之前是否将这些功能孤立在单独模块中的困境.

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 用户模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-30 07:29