RAILS我应该使用什么样的关系?

时间:2015-12-13 14:59:24

标签: ruby-on-rails database ruby-on-rails-4

在我的项目中,我陷入了一个问题:项目应该能够使用至少一种语言,语言有很多项目。我创建了这样的模型:

class Project < ActiveRecord::Base
  belongs_to :developer, counter_cache: true
  has_many :languages

  validates :developer, presence: true
  validates :name, presence: true, uniqueness: true
  validates :description, presence: true

end

class Language < ActiveRecord::Base
  has_many :projects
end

我为DB添加了3种语言。 现在我应该能够用某种语言创建一个项目:

p = Project.create :developer_id=>"1", :language_id=>"2", :name=>"Project 1", :description=>"Sample project"

它说:

ActiveRecord::UnknownAttributeError: unknown attribute 'language_id' for Project.

我有这种ID的语言然后为什么它不能添加一个。这可能是语言的问题 - &gt;他们没有项目,但有关系:has_many:projects

期待收到你们的回复:

编辑: 现在它看起来像:

class Language < ActiveRecord::Base
  has_and_belongs_to_many :projects
end

class Project < ActiveRecord::Base
  belongs_to :developer, counter_cache: true

  has_and_belongs_to_many :languages

  validates :developer, presence: true
  validates :name, presence: true, uniqueness: true
  validates :description, presence: true

end

我使用了rails g migration CreateProjectsLanguages project:references language:references

它返回:

p.languages.build(:name => "English")
PG::UndefinedTable: BŁĄD:  relacja "languages_projects" nie istnieje
LINE 5:                WHERE a.attrelid = '"languages_projects"'::re...
                                          ^
:               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
                FROM pg_attribute a LEFT JOIN pg_attrdef d
                  ON a.attrelid = d.adrelid AND a.attnum = d.adnum
               WHERE a.attrelid = '"languages_projects"'::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum

ActiveRecord::StatementInvalid: PG::UndefinedTable: BŁĄD:  relacja "languages_projects" nie istnieje
LINE 5:                WHERE a.attrelid = '"languages_projects"'::re...
                                          ^
:               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
                FROM pg_attribute a LEFT JOIN pg_attrdef d
                  ON a.attrelid = d.adrelid AND a.attnum = d.adnum
               WHERE a.attrelid = '"languages_projects"'::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum

它看起来无法找到它们之间的关系(可能关联表应该看起来不同)

2 个答案:

答案 0 :(得分:3)

您应该为多对多关系使用关联表。在rails中,您可以使用has_many:models映射实体,通过:associative_table_name。

class Project < ActiveRecord::Base
  has_many :language_projects
  has_many :projects, through: :language_projects
end

class LanguageProject < ActiveRecord::Base
  belongs_to :project
  belongs_to :language
end

class Language < ActiveRecord::Base
  has_many :language_projects
  has_many :projects, through: :language_projects
end

http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

在您的情况下,您可以为关联表生成模型和迁移:

rails g model LanguageProject project:references language:references

如果您不需要将关联表用作模型,则可以使用has_and_belongs_to_many直接映射实体。

class Project < ActiveRecord::Base
  has_and_belongs_to_many :languages
end

class Language < ActiveRecord::Base
  has_and_belongs_to_many :projects
end

在这种情况下,您只能生成迁移。您将只获得空壳,因此您必须手动编辑文件

rails g migration CreateLanguagesProjectsJoinTable

class CreateLanguagesProjectsJoinTable < ActiveRecord::Migration
  def change
     create_table :languages_projects, id: false do |t|
       t.integer :language_id
       t.integer :project_id
     end
  end
end

然后你应该能够以这种方式关联模型

p = Project.new(:name => 'myproj')
p.languages.build(:name => 'ruby')
p.save

答案 1 :(得分:0)

使用has_many :throughhas_and_belongs_to_many。它们的机制是相同的,除了has_many :through有其他模型。