I'm currently creating a many-to-many relationship between "Post" and "tags" through "Post_tags". What I want is to be able to save 4 things(title, content, tags, user_id) to my backend so that I can display or update posts. Currently, I'm able to save new post and update posts without tags. My current models are looking like this:
Post Model
class Post < ApplicationRecord
belongs_to :user
has_many :post_tags
has_many :tags, through: :post_tags
end
Post_tag Model
class PostTag < ApplicationRecord
belongs_to :post
belongs_to :tag
end
Tags Model
class Tag < ApplicationRecord
has_many :post_tags
has_many :posts, through: :post_tags
end
And I'm using React frontend to add new post with fetch request
export default function Post({currentUser}){
const[title, setTitle] = useState("");
const[content, setContent] = useState("");
const[tags, setTags] = useState("");
const user_id = currentUser.id
const navigate = useNavigate();
function handleSubmit(e){
e.preventDefault();
const newPost = {
title,
content,
user_id
}
fetch(`/post`, {
method: 'POST',
headers: {"Content-Type": 'application/json'},
body: JSON.stringify(newPost),
}).then((r) =>{
if (r.ok){
r.json().then(navigate('/profile'))
alert("New post created!")
}else{
alert("New post creation failed")
}
})
}
return(
<div className="post-form-container">
<form className="post-form" onSubmit={handleSubmit}>
<label>Title</label><br/>
<input
className='title-input'
type='text'
onChange={(e) => setTitle(e.target.value)}
value={title}>
</input><br/>
<label>Content</label><br/>
<textarea
className="content-input"
type='text'
onChange={(e) => setContent(e.target.value)}
value={content}
placeholder="Start typing~">
</textarea><br/>
<label>Tags: seperated by commas</label><br/>
<input
className="tags-input"
type='text'
onChange={(e) => setTags(e.target.value)}
value={tags}>
</input><br/>
<button className="post-btn" type="submit">Submit</button>
</form>
</div>
Lastly, My schema file is like this:
ActiveRecord::Schema[7.0].define(version: 2022_06_07_003341) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "post_tags", force: :cascade do |t|
t.integer "post_id"
t.integer "tag_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.string "content"
t.string "tags"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "username"
t.string "email"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
My question is how should I send "Tag" input from frontend to my backend to save in my case? Do I need to create another POST request for tag since tag is in separate table? I'm a beginner in Rails and please help.
CodePudding user response:
Add accepts_nested_attributes_for :tags
to your Post
model
class Post < ApplicationRecord
has_many :post_tags
has_many :tags, through: :post_tags
accepts_nested_attributes_for :tags
end
And tags_attributes: tags.split(',').map((el) => { return {name: el} })
to your newPost
variable
const newPost = {
title,
content,
user_id,
tags_attributes: tags.split(',').map((el) => { return {name: el} })
}
Also you need to add tags_attributes: %i[name]
to your strong params in Post
controller