将用户模型与数组关联

时间:2013-10-13 00:10:51

标签: ruby-on-rails ruby activerecord database-design

所以在我的rails应用程序中,我正在创建一个用户表,在该表中我有“电子邮件,密码和图像”等列。我想添加一个用户可以关联的具体国籍列表。

所以,我创建了一个用户模型: rails g model用户邮箱密码image:string

现在我想要一系列国籍......所以我没有创建一个数组,而是为国籍创建了一个单独的模型,并希望将它与我的用户联系起来。假设一个人可以有多个国籍,我就这样设置:

rails g model国籍名称:string

所以在user.rb中我写道: has_many:国籍

并在nationality.rb中写道: belongs_to:user

当用户注册时,我会有一个列表供他们选择:美国,加拿大,法国等... 我的直觉告诉我这可能是一个反模式,因为用户不会在列表中添加新的国籍...只选择,但管理员可以随时添加更多的国籍。

我没有收到任何错误,但它也不利于我。 我是否正确设置了,还是应该使用数组并将其存储在用户表中名为“国籍”的列下?

3 个答案:

答案 0 :(得分:0)

这实际上是一个数据库设计问题,而不是Rails问题,但我只是将Nationality表作为下拉列表的源,但User表只有{nationality表。 1}}列。我不认为需要额外的加入。当然,nationality列中的值来自用Nationality表填充的下拉列表中的用户选择。

但是,您的需求可能会有所不同。如果需要多个国籍,请坚持加入。正如Knuth所说,“过早优化是万恶之源。”

答案 1 :(得分:0)

您使用的是Rails 4吗? Postgresql是你的DB吗?如果是这样,这种组合允许您在用户模型上存储数组。

基本上,您可以将迁移修改为:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name # or whatever attributes you've already defined

      t.string :nationalities, array: true, default: []
      t.timestamps
    end
  end
end

您的ActiveRecord模型将包含以下内容:

class User < ActiveRecord::Base
  attr_accessible :nationalities
end

这将允许您创建如下的国籍列表:

user = User.create(name: 'Bob', nationalities: ['English', 'Australian', 'French'])

显然提取它们就像:

user.nationalities
=> ['English', 'Australian', 'French']

但是,关于在用户上建立关联或专栏的决定超出了在表单中创建具有国籍的用户的便利性。真正的问题是&#34;国籍在应用程序中扮演什么角色?意思是,国籍是否有额外的数据可以保证它是自己的模型?或者,它可以只是坐在用户表中吗?

如果国籍具有与用户名一样多的功能,那么它可以留在用户身上。但是,如果国籍可以有其他属性,例如&#39; date_aquired&#39;而不是它可能是它自己的模型。

答案 2 :(得分:0)

编辑:哎呀,我没有解决有多个国籍的问题。您可能需要考虑使用acts_as_taggable_on

https://github.com/mbleigh/acts-as-taggable-on

它可以很好地处理标记的多对多行为,并具有一些内置的便利性。

我认为现在可以为民族使用某种全局数组(在命名空间中),因为正如你所说的那样,民族的种类不会改变。

然而,我认为事情会比直接数组稍微复杂一点......你说你会给出American, Canadian, French之类的选择......那很好,但是如果是查看是否要求使用U.S., Canada, France?然后你的数组变成了哈希......我怀疑它会变得足够复杂,需要一个完整的Rails模型。一个简单的Hash应该涵盖大多数用例。

我发现在这种情况下创建单独的类或模块很有帮助。例如,对于Gender,绝对不值得创建一个单独的数据库表...然而,即使我存储在用户的gender列中的所有内容都是“M”,“F”,“O”(对于其他,或者可能没有指定),我将创建一个可以处理该域逻辑的Gender模块:

class Gender

   # better to make this private so that
   # only the factory constructor is exposed 
   def initialize(g)
     @g = g 
   end 

   def to_s  # and equivalent methods for serializing Gender into a M/F for database 
     return @g.to_s
   end 

   def pronoun 
     case @g
     when :M
       'he' 
     when :F
       'she'
     else
       'they'
   end 

end

def Gender(str) 
    case str
    when /^(?:m|male|man|boy)$/i
     Gender.new(:M)
    when /^(?:f|female|woman|girl)$/i
     Gender.new(:F)
    else 
     Gender.new(:O)
    end 
end