【问题标题】:How do I set up the rails models in a has_and_belongs_to_many relationship?如何在 has_and_belongs_to_many 关系中设置 rails 模型?
【发布时间】:2015-11-24 02:22:04
【问题描述】:

我正在开发一个博客 Rails 应用程序。我想让每个帖子都有很多标签,并且能够显示属于给定标签的所有帖子。我已经按照Rails Guide 设置了has_and_belongs_to_many 关系,我还尝试了this tutorial

在模型设置好后,我两次进入 Rails 控制台检查表格的格式是否正确。我打电话给Post.newTag.new。每个都在表中给我一个新的实例/条目,但都没有显示用于引用另一个的列。不应该有一个吗?如果没有,我应该如何构建我的种子数据?

到目前为止,我只处理了belongs_to 和has_many 关系。如果有人在has_and_belongs_to_many 上有一个更好的解释/教程的链接,我也将不胜感激,我的搜索并没有很清楚。

这是我的代码:

post.rb:

class Post < ActiveRecord::Base
  has_and_belongs_to_many :tags
  belongs_to :categories
end

tag.rb:

class Tag < ActiveRecord::Base
  has_and_belongs_to_many :posts
end

longnumber_create_posts.rb:

class CreatePosts < ActiveRecord::Migration
  def change
    create_table :posts do |t|
      t.string :name
      t.string :content
      t.datetime :pub_time
      t.integer :category_id
      t.timestamps null: false
    end
  end
end

lognumber_create_tags.rb:

class CreateTags < ActiveRecord::Migration
  def change
    create_table :tags do |t|
      t.string :name
      t.timestamps null: false
    end
  end
end

longnumber_create_posts_and_tags.rb:

class CreatePostsAndTags < ActiveRecord::Migration
  def change
    create_table :posts_tags, id: false do |t|
      t.belongs_to :post, index: true
      t.belongs_to :tag, index: true
    end
  end
end

schema.rb:

ActiveRecord::Schema.define(version: 20151123235501) do

  create_table "posts", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "posts_tags", id: false, force: :cascade do |t|
    t.integer "post_id"
    t.integer "tag_id"
  end

  add_index "posts_tags", ["post_id"], name: "index_posts_tags_on_post_id"
  add_index "posts_tags", ["tag_id"], name: "index_posts_tags_on_tag_id"

  create_table "tags", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end

【问题讨论】:

  • 如果你能把你的数据库结构和你的模型贴在这里就好了。

标签: ruby-on-rails ruby has-and-belongs-to-many


【解决方案1】:

在多对多关系中,使用您的示例,您不会在 Post 或 Tag 表中看到外键,因为它使用您创建的名为 PostTags 的“连接”表来存储关系。由于您已经在 3 个模型(Post、Tag、PostTag)中设置了 has_many 和 belongs_to 关联,您现在必须告诉 Rails 何时创建这些帖子和标签之间的关联。这样做如下:

@post = Post.new
@tag = Tag.last (The last is just an example, make sure to use the instance you need!

@post.tags << @tag   #This is where the magic happens and the association is formed

最近大多数 Rails 社区已经转向使用“has_many through”方法,因为它允许将额外的属性添加到连接表中,而在这里您只能将外键存储在 PostTag 表中。

更新:根据以下有关此代码去向的 cmets:

通常这会在您的控制器中执行,但您也可以在 rails 控制台中执行此操作。例如,如果您为帖子输入了一些表单输入,并在提交表单时添加了一个标签 ID 来关联它,那么您的控制器很可能看起来像这样:

def create
@post = Post.create(post_params)
if @post.save
@tag = Tag.find(params[:tag_id])
@post.tags << @tag
redirect_to some_fun_path
else
render 'new'
end


private

def post_params
   params.require(:post).permit(:tag_id, :title, :description, etc.)
end

【讨论】:

  • 您是在 Rails 控制台中调用它还是在文件中调用它?
  • 通常这会在您的控制器中进行,但您也可以在 Rails 控制台中执行此操作。例如:
【解决方案2】:

您已经分别实例化了一个 Tag 和 Post,但需要让一个对象知道另一个对象。此关联是在您创建的连接表中建立的。您可以通过以下几种方式建立这些关联:

选项 1

Post.create(name: text) # assuming your db was empty, this post now has id = 1
Tag.create(name: text, post_id: 1)

选项 2

post = Post.create(name: text)
tag = Tag.create(name: text)

# associate tag with post
post.tags << tag

选项 2 可能更可取,通常可以在您的控制器中调用。例如:

# in PostsController
def create
  post = Post.create(post_params)
  tag = Tag.find_or_create_by(params[:tag_id])
  post.tags << tag

  render root_path
end

private

  def post_params
    params.require(:post).permit(:name, :content, :pub_time, :category_id, :tag_id)
  end

【讨论】:

    【解决方案3】:

    您需要在Tag 和/或Post 上调用create,否则记录不会存储在数据库中。

    您将在下面创建一个帖子以及与该帖子相关的标签。

    post = Post.create!(content: "my content")
    post.tags.create!(name: "movies")
    

    【讨论】:

      【解决方案4】:

      您可以将TagPost 视为一个数组。例如:

      post = Post.create!(title: 'title')

      tag = Tag.create!(name: 'test')

      tag.posts &lt;&lt; post

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-21
        • 2016-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多