Nested attributes with Reactjs
Bài đăng này đã không được cập nhật trong 7 năm
Xin chào các bạn. Hôm nay mình xin chia sẻ với các bạn cách sử dụng nested attributes với react mà mình biết.
Chắc hẳn khi làm việc với rails các bạn cũng làm với nested attributes sử dụng form for. Form_for đã xây dựng sẵn params truyền lên controller cho các bạn. Tuy nhiên với Reactjs thì sao khi không có form_for cho các bạn sử dụng??? Với bài này hi vọng các bạn hiểu hơn về cách truyền params lên khi sử dụng nested attribute!!!
1. Bài toán đưa ra.
Question có nhiều answer. Khi tạo Question thì mình tạo answer sử dụng nested_attributes.
2. Xây dựng ứng dụng
Tạo project
cd work_space # Vào thư mục work_space
rails new my_app_nested_attributes
cd my_app_nested_attributes
bundle
Tạo model
rails g model Question title:string
rails g model Answer title:string question_id:integer is_correct:boolean
- Ta có question 1-n answer
- Add nested_attributes vào trong model question
class Question < ApplicationRecord
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, allow_destroy: true
end
- Association trong model Answer
class Answer < ApplicationRecord
belongs_to :question
end
Tạo controller để create question
rails g controller Questions --skip-assets
class QuestionsController < ApplicationController
def create
@question = Question.new question_params
if @question.save
render json: {message: "Create success", question: @question}, status: :ok
else
render json: {mesage: "Create fail", error: @question.errors}, status: :500
end
end
private
def question_params
params.require(:question).permit :title, answers_attributes: [:id, :title, :is_correct, :_destroy]
end
end
Tạo routes
#config/routes.rb
resources :question, only: :create
3. Client with Reactjs
- Tới đây bạn phải có 1 app react rồi thì ms thực hiện được
- Chúng ta sử dụng axios để gửi request từ client lên server
- Sử dụng FormData để lưu dữ liệu
#form question
import React from 'react';
import axios from 'axios';
import ReactOnRails from 'react-on-rails';
export default class FormQuestion extends React.Component {
constructor(props) {
super(props);
this.state = {
title: ' ',
answer_detail: {
title: ' ',
is_correct: ' '
},
answers: [ ]
}
}
render() {
return(
<form onSubmit={this.handleSubmitCreateQuestion.bind(this)}>
<div className='form-group'>
<input type='text' placeholder='title' value={this.state.title}
className='form-control' name='title'
onChange={this.handleChange.bind(this)} />
</div>
<button className='btn btn-success' type='submit'>Create</button>
</form>
<form>
<div className='form-group'>
<input type='text' placeholder='title' value={this.state.answer_detail.title}
className='form-control' name='title'
onChange={this.handleChangeAnswer.bind(this)} />
</div>
<div className='form-group'>
<input type='text' placeholder='title' value={this.state.answer_detail.is_correct}
className='form-control' name='title'
onChange={this.handleChangeAnswer.bind(this)} />
</div>
<button className='btn btn-success' onClick={this.handleAddAnswer.bind(this)}>
Add answer
</button>
</form>
);
}
// Thay đổi input form answers
handleChangeAnswer(e) {
let attribute = event.target.name;
Object.assign(this.state.answer_detail, {[attribute]: event.target.value});
this.setState({
answer_detail: this.state.answer_detail
});
}
// Thay đổi input form question
handleChange(e) {
let attribute = event.target.name;
Object.assign(this.state.title, {[attribute]: event.target.value});
this.setState({
title: this.state.title
});
}
//Add answer vào mảng answers
handleAddAnswer(e) {
e.prevenDefault();
this.state.answers.push(this.state.answer_detail);
this.setState({
answers: this.state.answers,
anser_detail: {
title: ' ',
is_correct: ' '
}
})
}
//gửi len sever
handleSubmitCreateQuestion(e) {
e.preventDefault();
let formData = new FormData();
formData.append('question[title]', this.state.title);
//Đoạn code dưới này đây là đế xử lý params truyền lên controller
this.state.answers.map((answer_detail, index) => {
formData.append('question[answers_attributes]['+ index +'][title]', answer_detail.title );
formData.append('question[answers_attributes]['+ index +'][is_correct]', answer_detail.is_correct );
}
formData.append('authenticity_token', ReactOnRails.authenticityToken()); //Token with react-on-rails sinh ra.
axios({
url: 'https://localhost:3000/questions,
method: 'POST',
data: formData
})
.then(response => {
alert('success');
})
.catch(error => {
console.log(error);
});
}
}
Trên đây là cách mà sử dụng nested_attribute với view tachs biệt rails. Bài viết có gì sai sót mong mọi người góp ý.
Note*: Quan trọng các ban có thể add được params vào request lên controller là oke. Các bạn byebug vào controller để xem params nhé. rất hay đó.
Gợi ý*: Các bạn có thể sử dụng create reactjs với webpack react-on-rails để tạo một ứng dụng sử dụng react trong rails https://github.com/shakacode/react-webpack-rails-tutorial
All rights reserved