Home > Blockchain >  Question regarding many-to-many relationship (Rails and React)
Question regarding many-to-many relationship (Rails and React)

Time:06-13

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

  • Related