Rails错误:has_many:通过连接

时间:2012-08-30 13:41:34

标签: ruby-on-rails ruby activerecord

我有一个ActiveRecord类:

class Post < ActiveRecord::Base
  has_many :posts_tags
  has_many :tags, :through => :posts_tags
end

class Tag < ActiveRecord::Base
  has_many :posts_tags
  has_many :posts, :through => :posts_tags  
end
class PostsTags < ActiveRecord::Base
  belongs_to :posts
  belongs_to :tags
end

当我想获得帖子标签时:

 <% @posts = Post.all %>
    <% @posts.each do |post| %>
       <% if post.tags.count != 0 %>
          <div class="post-tags">
          <% post.tags.each do |tag| %>
             <span><%= tag.name%></span>
          <%end%>
          </div>    
       <%end%>
    <% end %>

我收到错误uninitialized constant Post::PostsTag 我该如何解决这个问题?

3 个答案:

答案 0 :(得分:1)

您传递给belongs_to的名称应该是单数:

belongs_to :post
belongs_to :tag

修改

此外,该模型应命名为PostsTag。 ActiveRecord期望所有模型名称都是单数的,并且与多个表名匹配。确保您的表名是'posts_tags'。

答案 1 :(得分:1)

引用ActiveRecord文档:

  

选择构建多对多关系的方式并不总是很简单。如果您需要将关系模型作为自己的实体使用,请使用has_many:through。在使用旧模式时或者从不直接使用关系本身时,请使用has_and_belongs_to_many。

由于您似乎只使用PostsTags类进行加入,因此您应该考虑切换到has_and_belongs_to_many

class Post < ActiveRecord::Base
  has_and_belongs_to_many :tags       # foreign keys in the join table
end
class Tag < ActiveRecord::Base
  has_and_belongs_to_many :posts    # foreign keys in the join table
end

您应该已经有一个posts_tags表格,其中包含post_id课程中的tag_idPostsTags列。如果没有,那么你需要创建一个。除非在声明关系时为连接表指定自定义名称,否则表必须命名为posts_tags。可能的迁移可能如下所示:

class CreatePostsTagsJoinTable < ActiveRecord::Migration
  def change 
    create_table :posts_tags, :id => false do |t|
      t.integer :post_id
      t.integer :tag_id
    end
  end
end

然后您应该删除app/models/posts_tags.rb文件,因为has_and_belongs_to_many关系,“[t]他连接表不应该有主键或与之关联的模型。” - ActiveRecord :: Associations :: ClassMethods

documentation for this method提供了有关命名连接表和优化性能的更多信息。

答案 2 :(得分:1)

你有多对多的关系,你应该阅读A Guide to Active Record Associations

你所拥有的并不是很困难,但确实需要一些研究。作为一个简单的规则:如果您要使用关联(例如,您想要将描述存储到PostTag),请使用以下代码。如果不是:请使用之前帖子中已涵盖的has_and_belongs_to_many。在代码下方,使用迁移,模型和视图:

class Post < ActiveRecord::Base
  has_many :post_tags
  has_many :tags, :through => :post_tags
end

class Tag < ActiveRecord::Base
  has_many :post_tags
  has_many :posts, :through => :post_tags  
end

class PostTag < ActiveRecord::Base
  belongs_to :post
  belongs_to :tag
end

您的迁移应该如下所示:

class CreateTables < ActiveRecord::Migration
  def self.up
    create_table :tags do |t|
      # some other attributes here

      t.timestamps
    end

    create_table :posts do |t|
      # some other attributes here

      t.timestamps
    end

    create_table :post_tags do |t|
      # some other attributes here
      t.references :post
      t.references :tag

      t.timestamps
    end
  end

  def self.down
    drop_table :tags
    drop_table :posts
    drop_table :post_tags
  end
end

您的观点应如下所示:

<% @posts = Post.all %>
    <% @posts.each do |post| %>
       <% if post.tags.any? %>
          <div class="post-tags">
          <% post.tags.each do |tag| %>
             <span><%= tag.name %></span>
          <%end%>
          </div>    
       <%end%>
    <% end %>