将表拆分为两个关联的表 [英] Split table into two associated tables

查看:32
本文介绍了将表拆分为两个关联的表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有博客功能的应用.最初,当我设置此帖子时,帖子由标题、正文、关键字和图片链接组成.我希望能够根据关键字过滤帖子,我认为最简洁的方法是将关键字移动到他们自己的表并将这两个表关联起来.所以每个帖子可以有多个关键词,每个关键词可以有多个帖子.

I have an app that has a blog feature. Originally when I set this up a post post consisted of a title, body, keywords, and image link. I want to be able to filter posts based on keywords and I think the cleanest way to do this is to move keyword to their own table and associate the two tables. So each posts can have multiple keywords and each keyword can have multiple posts.

我为关键字创建了迁移和模型.

I created a migrations and model for keywords.

class CreateKeywords < ActiveRecord::Migration[6.1]
  def change
    create_table :keywords do |t|
      t.string :keyword

      t.timestamps
    end
  end
end

class Keyword < ApplicationRecord
  has_and_belongs_to_many :posts
end

我将其与帖子表相关联并更改了帖子模型.

I associated that with the posts table and changed the posts model.

class CreatePostsKeywordsJoinTable < ActiveRecord::Migration[6.1]
  def change
    create_join_table :posts, :keywords do |t|
      t.index [:post_id, :keyword_id]
      t.index [:keyword_id, :post_id]
    end
  end
end

class Post < ApplicationRecord
  belongs_to :user
  has_and_belongs_to_many :keywords

  validates :title, presence: true
  validates :body, presence: true

  accepts_nested_attributes_for :keywords
  # validates :keywords, presence: true
  
end

现在我只是注释掉了 Post 模型中的关键字.我不确定是否需要删除它.我已经有一些现有的帖子,我不想在此切换过程中丢失这些帖子,因此在我弄清楚如何进行这项工作时,我会尽量记住这一点.我真正感到困惑的是我需要在控制器中更改什么.

For now I just commented out the keywords in the Post model. I'm not exactly sure if I need to remove it or not. I already have existing posts that I don't want to lose as part of this switchover so I'm trying to keep that I mind as I figure out how to make this work. Where I'm really confused is what I need to change in the controller.

这是我的帖子控制器:

require 'pry'

class Api::V1::PostController < ApiController
  before_action :authorize_user, except: [:index, :show]

  # INDEX /post
  def index
    render json: Post.all, each_serializer: PostSerializer
  end

  # SHOW /post/1
  def show
    render json: Post.find(params[:id]), serializer: PostShowSerializer
  end

  # CREATE /post/new
  def create
    binding.pry
    post = Post.new(post_params)
    post.user = current_user

    if post.save
      render json: post
    else
      render json: { errors: post.errors.full_messages }
    end 

  end

  # UPDATE /post/update
  def update
    post = Post.find(params[:id])

    if post.update(post_params)
      render json: post
    else
      render json: { errors: post.errors.full_messages }
    end
  end

  # DESTROY /post/destroy
  def destroy
    post = Post.find(params[:id])
  
    if post.destroy
      render json: {destroyed: true}
    end
    
  end
  
  protected

  def post_params
    params.require(:post).permit([:title, :body, :image, :keywords])
  end

  def authorize_user
    if !user_signed_in? || current_user.role != "admin"
      redirect_to root_path
    end
  end

end

在上述状态下,当我进入这部分 post = Post.new(post_params) 我收到一个错误消息,说 NoMethodError (undefined method 'each' for "authorlife":String).如果我从 post_params 中删除 keywords 我得到这个错误 Unpermitted parameter: :keywords

In the above state when I get to this part post = Post.new(post_params) I get an error saying NoMethodError (undefined method 'each' for "authorlife":String). If I remove keywords from the post_params I get this error Unpermitted parameter: :keywords

我觉得我在这里遗漏了一个或多个步骤,但我已经有一段时间没有对这样的关联表做过任何事情了.

I feel like I am missing one or more steps here but it's been awhile since I've done anything with associated tables like this.

更新:遵循下面的一些建议,我将上面的代码更新为当前的样子.当前的问题是,当我在 #create 方法中检查 post_parms 时,我根本不再收到关键字.我检查了前端,它正在发送关键字.我假设是我的 post_params 导致了问题.我试过像这样添加关键字嵌套属性,但关键字仍然没有出现在 post_params

UPDATE: Followed some of the advice below and I updated the above code to how it currently looks. Current issue is that when I check post_parms in the #create method I'm no longer receiving keywords at all. I checked the frontend and it's sending keywords. I'm assuming it's my post_params that's causing the problem. I've tried adding the keywords nested attribute like this but keywords still isn't showing up in the post_params

def post_params
    params.require(:post).permit(:title, :body, :image, :keywords_attributes => [:id, :keyword])
  end

这是我尝试实现的代码的 WIP.一旦我弄清楚了 params 情况,我不确定关键字部分应该是什么样子.

This is the WIP for the code I'm trying to implement. I'm not sure what the keywords part is supposed to look like once I get the params situation figured out.

params = { post: {title: post_params["title"], body: post_params["body"], image: post_params["image"], keywords_attributes: [{ keyword: 'keyword title' },]
}}

推荐答案

在上述状态下,当我到达这部分 post = Post.new(post_params) 时,我收到一条错误消息,指出 NoMethodError(authorlife"的未定义方法 'each':String).如果我从 post_params 中删除关键字,我会收到此错误 Unpermitted parameter: :keywords

In the above state when I get to this part post = Post.new(post_params) I get an error saying NoMethodError (undefined method 'each' for "authorlife":String). If I remove keywords from the post_params I get this error Unpermitted parameter: :keywords

如果您想通过帖子更新关键字,您需要为关键字设置嵌套属性.

You need to setup nested attributes for keywords if you want to update them through a post.

class Post < ApplicationRecord
  belongs_to :user
  has_and_belongs_to_many :keywords

  validates :title, presence: true
  validates :body, presence: true

  accepts_nested_attributes_for :keywords
end

然后您可以在控制器中传入这样结构的参数

You can then pass in params structured like this in your controller

params = { post: {
  title: 'title', body: "body", keywords_attributes: [
    { text: 'keyword title' },
  ]
}}

post = Post.create(params[:post])

https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

我已经有一些现有的帖子,我不想在这次转换过程中丢失这些帖子,所以我在想办法让这项工作顺利进行时,我会尽量记住这一点.

I already have existing posts that I don't want to lose as part of this switchover so I'm trying to keep that I mind as I figure out how to make this work.

最好再删除这些未使用的数据.您应该编写一个数据迁移,将现有关键字从帖子表移动到关键字表.像这样

It's good practice to remove this not used data anymore. You should write a data migration which moves the existing keywords from the posts table to the keywords table. Something like this

class KeywordsMigrator
  def run
    Post.all.each do |post|
      keyword = Keyword.find_or_create_by(title: post.keyword)
      post.keywords << keyword
    end
  end
end

最后,您可以从帖子中删除 keyword 列.

Finally you can drop the keyword column from post.

您还没有真正提到帖子表的当前结构,所以我假设您在那里有一个 keyword 列.如果您有一个 keywords 列,则必须将关联命名为不同的名称,直到删除该列,否则会遇到麻烦.例如,您将其重命名为 keywords_v1 并指定 class_name.

You haven't really mentioned the current structure of the posts table so I assume you have a keyword column there. If you have a keywords column you have to name your association different until you remove the column otherwise you will run into troubles. For example you rename it to keywords_v1 and specify the class_name.

class Post < ApplicationRecord
  belongs_to :user
  has_and_belongs_to_many :keywords_v1, class_name: "Keyword"

  validates :title, presence: true
  validates :body, presence: true  
end

或者您首先将列重命名为 deprecated_keywords 之类的名称.

Or you rename the column first to something like deprecated_keywords.

这篇关于将表拆分为两个关联的表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆