将表拆分为两个关联的表 [英] Split table into two associated tables
问题描述
我有一个具有博客功能的应用.最初,当我设置此帖子时,帖子由标题、正文、关键字和图片链接组成.我希望能够根据关键字过滤帖子,我认为最简洁的方法是将关键字移动到他们自己的表并将这两个表关联起来.所以每个帖子可以有多个关键词,每个关键词可以有多个帖子.
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屋!