4

I am creating a React-Rails app, using ES6, and I am having difficulty passing data from the controller to the component (and back).

My app includes a record form that pushes the newly created record to the records component.

The code within my Records controller is:

class RecordsController < ApplicationController
    def index
        @records = Record.all
    end

    def create
        @record = Record.new(record_params)

        if @record.save
            render json: @record
        else 
            render json: @record.errors, status: :unprocessable_entity
        end

    end


    private
        def record_params
            params.require(:record).permit(:title, :date, :amount)
        end

end

The code for Records component is:

class Records extends React.Component {
    constructor (props) {
        super(props);

    }
    componentWillMount () {
        var records = this.records;
        this.state = {records: records};
    }
    addRecord (record) {
        var records;
        records = this.state.records;
        records.push(record);
        this.setState({records: records});
    }
      render () {
        var records = this.records.map(function(record) {
                        return <Record key={record.id} data={record} />;
                        });

        return (        
                <div>
                    <h2>Records</h2>
                    <RecordForm handleNewRecord={this.addRecord()} />
                    <table>
                        <thead>
                            <tr>
                                <th>Title</th>
                                <th>Date</th>
                                <th>Amount</th>
                            </tr>
                        </thead>
                        <tbody>
                            {records}
                        </tbody>
                    </table>
                </div>
        );
      }
}

The code for the Record Form component is:

class RecordForm extends React.Component {
  constructor (props) {
    super (props);
    this.state = {
      title: "",
      date: "",
      amount: ""
    }
    this.handleNewRecord = this.props.handleNewRecord.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange (e) {
    var stateObject = function() {
      returnObj = {};
      returnObj[this.target.name] = this.target.value;
         return returnObj;
    }.bind(e)();

    this.setState( stateObject ); 
    }

  handleSubmit (e) {
    e.preventDefault();
    $.ajax({
      type: 'POST',
      url: '',
      data: {record: this.state},
      success: function (data) {
                  this.props.handleNewRecord();
                  this.setState({title: "", date: "", amount: ""})
              },
      dataType: 'JSON'
    });
  }
  render () {
    return (
          <form className="form-inline" onSubmit={this.handleSubmit} >
            <div className="form-group">
              <input  
                type="text" 
                className="form-control text" 
                placeholder="Date"
                name="date"
                value={this.state.date}
                onChange={this.handleChange}
              />
              </div>
            <div className="form-group">
              <input  
                type="text" 
                className="form-control" 
                placeholder="Title"
                name="title"
                value={this.state.title}
                onChange={this.handleChange}
              />
            </div>
            <div className="form-group">
              <input  
                type="text" 
                className="form-control" 
                placeholder="Amount"
                name="amount"
                value={this.state.amount}
                onChange={this.handleChange}
              />
            </div>
            <input 
                type="submit" 
                value="Create Record"
                className="btn btn-primary"
            />
          </form>
    );
  }
}

The code for the Record component is:

class Record extends React.Component {
  render () {
    return (
      <tr>
        <td><em>{this.props.data.title}</em></td>
        <td>{this.props.data.date}</td>
        <td>{this.props.data.amount}</td>
      </tr>
    );
  }
}

When I run this code, I receive the following error regarding the render method in the Records component:

Uncaught TypeError: Cannot read property 'map' of undefined

I apologize for the length of this question, but I have been working on it for a while and I am frankly flummoxed.

Does anyone have an idea why this not working? I completely appreciate any advice anyone can provide. Thanks!

1
  • Could you add your view code? For example, do you use the react_component helper? Commented May 18, 2016 at 21:00

2 Answers 2

4

this.records.map is undefined because records is undefined, didn't come down as instance var from controller after being instantiated as @records.

Had same issue with app/views/dashboard/show.html.erb that looked like this:

<%= react_component 'Dashboard', { flashes: flash, user: user}, :div %>

changed to this for the fix under react-rails, for me:

<%= react_component 'Dashboard', { flashes: flash, user: @user}, :div %>

in my case the instance variable was named @user...

Sign up to request clarification or add additional context in comments.

1 Comment

This is the easiest way to do it.
2

To pass data from your rails backend to react, you can use jbuilder, and pass the file when you render your component:

<%= react_component "RecordForm",
    render(template: 'records/form.json.jbuilder') %>

You now have to create a form.json.jbuilder file in your views/records folder:

 json.records do
   json.array! @records do |record|
     json.partial! "record", record: record
   end
 end

This is just an example as I don't know how your data is structured, but this is a good way to do it. To read more about it: https://github.com/rails/jbuilder

To send data from React to Rails, you should use ajax calls, triggered by events.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.