Ruby on rails React应用程序在本地主机上运行良好,但在Heroku上出错
今天的错误非常令人沮丧。我花了一整天的时间调试我的小应用程序,它在本地主机上运行得很好,但在heroku上偶尔会出错 如果我多次刷新页面,就可以实现登录。但它需要2-3次刷新 我在登录用户时遇到的两个错误是-Ruby on rails React应用程序在本地主机上运行良好,但在Heroku上出错,ruby-on-rails,reactjs,heroku,redux,Ruby On Rails,Reactjs,Heroku,Redux,今天的错误非常令人沮丧。我花了一整天的时间调试我的小应用程序,它在本地主机上运行得很好,但在heroku上偶尔会出错 如果我多次刷新页面,就可以实现登录。但它需要2-3次刷新 我在登录用户时遇到的两个错误是- Uncaught TypeError: Cannot read property 'exercise_name' of undefined 及 现在我基本上知道问题是什么了。当我最初尝试在道具上绘制地图时,我不能使用道具。其中一个道具是一系列练习,其中一个键是“练习名称”。我猜这与我从本
Uncaught TypeError: Cannot read property 'exercise_name' of undefined
及
现在我基本上知道问题是什么了。当我最初尝试在道具上绘制地图时,我不能使用道具。其中一个道具是一系列练习,其中一个键是“练习名称”。我猜这与我从本地主机接收到的速度有关,而不是与heroku的ajax调用有关
这是我的问题
我不知道这是来自哪个组件,因为我在4个组件中使用了exercise_name。Heroku有行号,但行号没有任何帮助,因为它没有指向我的应用程序中的任何内容,我不能像在我的机器上那样在Heroku中放置调试器
我尝试过在mapStateToProps中设置默认道具,如下所示-
allExercises: state.entities.exercise || []
不起作用
我试着在我的组件中用条件句包装东西。没用
以下四个组件使用练习名称。任何指示都将不胜感激
我知道下面有很多代码。如果有一个答案能让我知道如何找到在heroku上产生这些错误的代码行,或者如何在heroku上进行调试,我会非常满意
组成部分1
import React from 'react';
import { withRouter } from 'react-router-dom';
import SetResultContainer from '../setresult/create_setresult_container';
class ExerciseIndex extends React.Component {
constructor(props) {
super(props);
this.state = {
inputVal: '',
active: 'FIRST',
name: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ inputVal: e.target.value })
}
componentDidMount() {
this.props.requestAllExercises();
}
handleClick(e) {
this.setState({ inputVal: e.currentTarget.attributes.value.value})
}
handleSubmit(e) {
let newActive = this.state.active === 'FIRST' ? 'SECOND' : null
let allExercises = this.props.allExercises;
let selected;
let name;
if (allExercises) {
allExercises.forEach(exercise => {
if (exercise.exercise_name === this.state.inputVal) {
selected = exercise,
name = exercise.exercise_name
}
})
e.preventDefault();
}
if (!name) {
this.setState({inputVal: 'Invalid Input, Please try Again'})
return 'Invalid Input'
}
this.props.requestExercise(selected)
this.setState({inputVal: '', active: newActive, name: name})
this.props.requestAllExercises();
}
render() {
let allExercises = this.props.allExercises || [{ exercise_name: '' }]
let match = allExercises.map((exercise) => {
if (this.state.inputVal === '') return [];
let matched = [];
if (this.state.inputVal.length > 0) {
for (var j = 0; j < this.state.inputVal.length; j++) {
matched = [];
if (exercise.exercise_name.slice(0, j + 1).toUpperCase() === this.state.inputVal.slice(0, j + 1).toUpperCase()) {
matched.push(<li onClick={this.handleClick}
value={exercise.exercise_name}
className="workout-auto-li"
key={exercise.id}>{exercise.exercise_name}</li>);
}
}
} else {
matched.push(<li onClick={this.handleClick}
value={exercise.exercise_name}
className="workout-auto-li"
key={exercise.id}>{exercise.exercise_name}</li>)
}
return matched;
});
return (
<div>
{this.props.allExercises ? (
<div>
{this.state.active === 'FIRST' ? (
<div className="exercise-main-div">
<div className="exercise-second-div">
<label className="exercise-label">
<h3>Add an Exercise for {this.props.liftname}</h3>
<input type="text" value={this.state.inputVal}
onChange={this.handleChange}
className="exercise-input"
/>
</label>
<ul className="exercise-ul">
{match}
</ul>
<button className="new-exercise-button"
onClick={this.handleSubmit}>Add Exercise</button>
</div>
</div>
) : this.state.active === 'SECOND' ? (
<SetResultContainer user={this.props.user}
exercises={this.props.exercises}
exercise={this.state.name}
liftname={this.props.liftname}/>
) : null }
</div>
) : null }
</div>
);
}
}
export default withRouter(ExerciseIndex);
从“React”导入React;
从“react router dom”导入{withRouter};
从“../setresult/create_setresult_container”导入SetResultContainer;
类ExerciseIndex扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
输入值:“”,
活动:'第一',
名称:“”
};
this.handleChange=this.handleChange.bind(this);
this.handleClick=this.handleClick.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
手变(e){
this.setState({inputVal:e.target.value})
}
componentDidMount(){
this.props.requestAllExercises();
}
handleClick(e){
this.setState({inputVal:e.currentTarget.attributes.value.value})
}
handleSubmit(e){
让newActive=this.state.active=='FIRST'?'SECOND':null
让allExercises=this.props.allExercises;
让我们选择;
让名字;
如果(所有练习){
allExercises.forEach(练习=>{
if(exercise.exercise_name==this.state.inputVal){
选择=练习,
name=exercise.exercise\u name
}
})
e、 预防默认值();
}
如果(!name){
this.setState({inputVal:'无效输入,请重试'})
返回“无效输入”
}
this.props.requestExercise(已选择)
this.setState({inputVal:'',活动:newActive,name:name})
this.props.requestAllExercises();
}
render(){
让allExercises=this.props.allExercises | |[{exercise_name:''}]
让match=allExercises.map((练习)=>{
如果(this.state.inputVal=='')返回[];
让匹配=[];
如果(this.state.inputVal.length>0){
for(var j=0;j{exercise.exercise\u name});
}
}
}否则{
匹配的.push({exercise.exercise\u name} )
}
返回匹配;
});
返回(
{this.props.allExercises(
{this.state.active==='FIRST'(
为{this.props.liftname}添加一个练习
{match}
加练习
):this.state.active===‘秒’(
):null}
):null}
);
}
}
使用路由器导出默认值(ExerciseIndex);
构成部分2
import React from 'react';
import { withRouter } from 'react-router';
import values from 'lodash/values'
import { Pie } from 'react-chartjs-2';
class Leaderboard extends React.Component {
constructor(props) {
super(props)
this.state = { exercise: null }
this.handleUpdate = this.handleUpdate.bind(this)
}
componentDidMount() {
this.props.requestAllUsers();
this.props.requestAllExercises();
}
handleUpdate(property) {
return e => this.setState({ [property]: e.target.value });
}
render() {
const members = this.props.members.map(member => {
return <li className="members-list" key={member.id + 1}>{member.username}</li>
})
const memberId = {}
this.props.members.map(member => {
memberId[member.username] = member
})
const membersSetResults = {}
const membersLiftMaxes = {}
const completedMemberExercises = []
const completedExercises = {}
this.props.members.map(member => {
if (member.workouts) {
let workouts = values(member.workouts)
for (var i = 0; i < workouts.length; i++) {
let workoutResult = workouts[i].setresults
let results = values(workoutResult)
if (membersSetResults[member.username]) {
membersSetResults[member.username].unshift(results)
} else {
membersSetResults[member.username] = [results];
}
}
}
})
Object.keys(membersSetResults).map(member => {
let setResults = membersSetResults[member]
membersLiftMaxes[member] = {}
for (var i = 0; i < setResults.length; i++) {
let sets = setResults[i]
for (var j = 0; j < sets.length; j++) {
let currentExercise = this.props.allExercises[sets[j].exercise_id]
let exercise = currentExercise.exercise_name
if (completedMemberExercises.indexOf(exercise) < 0 && currentExercise.ex_type === 'lift') {
completedMemberExercises.push(exercise)
}
if (completedExercises[exercise]) {
completedExercises[exercise] += 1
} else if (!completedExercises[exercise]) {
completedExercises[exercise] = 1
}
if (currentExercise.ex_type === 'lift') {
if (membersLiftMaxes[member][exercise]) {
if(membersLiftMaxes[member][exercise] < sets[j].weight_lifted) {
membersLiftMaxes[member][exercise] = sets[j].weight_lifted
}
} else if (!membersLiftMaxes[member][exercise]) {
membersLiftMaxes[member][exercise] = sets[j].weight_lifted
}
}
}
}
})
const PieChart = {
datasets: [{
data: Object.values(completedExercises),
backgroundColor: [
'#2D4262',
'#363237',
'#73605B',
'#D09683',
'#F1F3CE',
'#1E656D',
'#00293C',
'#F0810F',
'#75B1A9',
],
}],
labels: Object.keys(completedExercises)
};
let exerciseDropdown = completedMemberExercises.map((exercise, idx) => {
return <option key={idx} value={exercise}>{exercise}</option>
})
let sorted = [];
const memberAndMax = {}
Object.keys(membersLiftMaxes).map(member => {
if (this.state.exercise) {
let exerciseMax = membersLiftMaxes[member][this.state.exercise]
if(!memberAndMax[this.state.exercise]){
memberAndMax[this.state.exercise] = []
memberAndMax[this.state.exercise].push([member, exerciseMax])
} else if (memberAndMax[this.state.exercise]) {
memberAndMax[this.state.exercise].push([member, exerciseMax])
}
memberAndMax[this.state.exercise].map(max => {
if (sorted.indexOf(max) < 0) {
if (max[1] > 0) {
sorted.push(max)
}
}
})
sorted.sort((a, b) => {
return a[1] - b[1]
})
}
})
let maxLis = sorted.reverse().map((user) => {
if (memberId[user[0]].id === this.props.cu.id) {
return <li className='userPresent' key={memberId[user[0]].id}>
<p className="members-list-p">{user[0]}</p>
<p className="members-list-p-two">{user[1]}</p></li>
} else {
return <li className='members-list' key={memberId[user[0]].id}>
<p className="members-list-p">{user[0]}</p>
<p className="members-list-p-two">{user[1]}</p></li>
}
})
return (
<div className='main-leaderboard'>
<div className='lb-reset-div'>
<button className='lb-reset-button' onClick={() => this.setState({exercise: null})}>Reset</button>
<select className='leaderboard-dropdown' onChange={this.handleUpdate('exercise')}>
<option>Please Select</option>
{exerciseDropdown}
</select>
</div>
{(this.state.exercise) ? (
<div className='lb-ul-div'>
<h3 className='selected-ex-title'>{this.state.exercise}</h3>
<ul className='leaderboard-ul'>
<li className="members-list"><p className="members-list-p">Name</p>
<p className="members-list-p-two">Max (lbs)</p></li>
{maxLis}
</ul>
</div>
): (!this.state.exercise) ? (
<div className='lb-ul-div'>
<h3 className='selected-ex-title'>Leaderboard</h3>
<ul className='leaderboard-ul'>
{members}
</ul>
</div>
): null}
<div className='pie-chart-div-lb'>
<h3 className='pie-chart-header'>What the World's Doing</h3>
<Pie circumfrence={300} data={PieChart}/>
</div>
</div>
)
}
}
export default withRouter(Leaderboard);
从“React”导入React;
从“react router”导入{withRouter};
从“lodash/values”导入值
从'react-chartjs-2'导入{Pie};
类排行榜扩展React.Component{
建造师(道具){
超级(道具)
this.state={exercise:null}
this.handleUpdate=this.handleUpdate.bind(this)
}
componentDidMount(){
this.props.requestAllUsers();
this.props.requestAllExercises();
}
handleUpdate(属性){
返回e=>this.setState({[property]:e.target.value});
}
render(){
const members=this.props.members.map(member=>{
return{member.username}
})
常量memberId={}
this.props.members.map(member=>{
memberId[成员.用户名]=成员
})
常量membersSetResults={}
常量membersLiftMaxes={}
const completedMemberExercises=[]
const completedExercises={}
this.props.members.map(member=>{
if(会员训练){
让训练=值(成员.训练)
对于(var i=0;iimport React from 'react';
import { withRouter } from 'react-router';
import values from 'lodash/values'
import { Pie } from 'react-chartjs-2';
class Leaderboard extends React.Component {
constructor(props) {
super(props)
this.state = { exercise: null }
this.handleUpdate = this.handleUpdate.bind(this)
}
componentDidMount() {
this.props.requestAllUsers();
this.props.requestAllExercises();
}
handleUpdate(property) {
return e => this.setState({ [property]: e.target.value });
}
render() {
const members = this.props.members.map(member => {
return <li className="members-list" key={member.id + 1}>{member.username}</li>
})
const memberId = {}
this.props.members.map(member => {
memberId[member.username] = member
})
const membersSetResults = {}
const membersLiftMaxes = {}
const completedMemberExercises = []
const completedExercises = {}
this.props.members.map(member => {
if (member.workouts) {
let workouts = values(member.workouts)
for (var i = 0; i < workouts.length; i++) {
let workoutResult = workouts[i].setresults
let results = values(workoutResult)
if (membersSetResults[member.username]) {
membersSetResults[member.username].unshift(results)
} else {
membersSetResults[member.username] = [results];
}
}
}
})
Object.keys(membersSetResults).map(member => {
let setResults = membersSetResults[member]
membersLiftMaxes[member] = {}
for (var i = 0; i < setResults.length; i++) {
let sets = setResults[i]
for (var j = 0; j < sets.length; j++) {
let currentExercise = this.props.allExercises[sets[j].exercise_id]
let exercise = currentExercise.exercise_name
if (completedMemberExercises.indexOf(exercise) < 0 && currentExercise.ex_type === 'lift') {
completedMemberExercises.push(exercise)
}
if (completedExercises[exercise]) {
completedExercises[exercise] += 1
} else if (!completedExercises[exercise]) {
completedExercises[exercise] = 1
}
if (currentExercise.ex_type === 'lift') {
if (membersLiftMaxes[member][exercise]) {
if(membersLiftMaxes[member][exercise] < sets[j].weight_lifted) {
membersLiftMaxes[member][exercise] = sets[j].weight_lifted
}
} else if (!membersLiftMaxes[member][exercise]) {
membersLiftMaxes[member][exercise] = sets[j].weight_lifted
}
}
}
}
})
const PieChart = {
datasets: [{
data: Object.values(completedExercises),
backgroundColor: [
'#2D4262',
'#363237',
'#73605B',
'#D09683',
'#F1F3CE',
'#1E656D',
'#00293C',
'#F0810F',
'#75B1A9',
],
}],
labels: Object.keys(completedExercises)
};
let exerciseDropdown = completedMemberExercises.map((exercise, idx) => {
return <option key={idx} value={exercise}>{exercise}</option>
})
let sorted = [];
const memberAndMax = {}
Object.keys(membersLiftMaxes).map(member => {
if (this.state.exercise) {
let exerciseMax = membersLiftMaxes[member][this.state.exercise]
if(!memberAndMax[this.state.exercise]){
memberAndMax[this.state.exercise] = []
memberAndMax[this.state.exercise].push([member, exerciseMax])
} else if (memberAndMax[this.state.exercise]) {
memberAndMax[this.state.exercise].push([member, exerciseMax])
}
memberAndMax[this.state.exercise].map(max => {
if (sorted.indexOf(max) < 0) {
if (max[1] > 0) {
sorted.push(max)
}
}
})
sorted.sort((a, b) => {
return a[1] - b[1]
})
}
})
let maxLis = sorted.reverse().map((user) => {
if (memberId[user[0]].id === this.props.cu.id) {
return <li className='userPresent' key={memberId[user[0]].id}>
<p className="members-list-p">{user[0]}</p>
<p className="members-list-p-two">{user[1]}</p></li>
} else {
return <li className='members-list' key={memberId[user[0]].id}>
<p className="members-list-p">{user[0]}</p>
<p className="members-list-p-two">{user[1]}</p></li>
}
})
return (
<div className='main-leaderboard'>
<div className='lb-reset-div'>
<button className='lb-reset-button' onClick={() => this.setState({exercise: null})}>Reset</button>
<select className='leaderboard-dropdown' onChange={this.handleUpdate('exercise')}>
<option>Please Select</option>
{exerciseDropdown}
</select>
</div>
{(this.state.exercise) ? (
<div className='lb-ul-div'>
<h3 className='selected-ex-title'>{this.state.exercise}</h3>
<ul className='leaderboard-ul'>
<li className="members-list"><p className="members-list-p">Name</p>
<p className="members-list-p-two">Max (lbs)</p></li>
{maxLis}
</ul>
</div>
): (!this.state.exercise) ? (
<div className='lb-ul-div'>
<h3 className='selected-ex-title'>Leaderboard</h3>
<ul className='leaderboard-ul'>
{members}
</ul>
</div>
): null}
<div className='pie-chart-div-lb'>
<h3 className='pie-chart-header'>What the World's Doing</h3>
<Pie circumfrence={300} data={PieChart}/>
</div>
</div>
)
}
}
export default withRouter(Leaderboard);
import React from 'react';
import { withRouter } from 'react-router';
import values from 'lodash/values';
import { Line, Pie } from 'react-chartjs-2';
class SearchBestWorkouts extends React.Component {
constructor(props) {
super(props);
this.state = {
inputVal: '',
name: '',
active: '',
result: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
this.props.requestAllExercises();
this.setState({active: 'FIRST'})
}
handleChange(e) {
e.preventDefault(e)
this.setState({ inputVal: e.target.value })
}
handleClick(e) {
this.setState({ inputVal: e.currentTarget.attributes.value.value})
}
handleSubmit(e) {
let newActive = this.state.active === 'FIRST' ? 'SECOND' : 'FIRST'
let allExercises = values(this.props.exercises);
let selected;
let name;
if (newActive === 'SECOND') {
allExercises.forEach(exercise => {
if (exercise.exercise_name === this.state.inputVal) {
selected = exercise,
name = exercise.exercise_name
}
})
e.preventDefault();
if (!name) {
this.setState({inputVal: 'Invalid Input, Please try Again'})
return 'Invalid Input'
}
this.setState({inputVal: '', active: newActive, name: name})
this.props.requestAllExercises();
} else if (newActive === 'FIRST') {
this.setState({inputVal: '', active: newActive, name: '' })
}
}
render () {
let allWorkouts = this.props.allWorkouts;
let exercises = this.props.exercises;
let setResults = allWorkouts.map(workout => {
return values(workout.setresults)
})
let mergedSets = [].concat.apply([], setResults)
const allResults = {}
const exerciseTypes = {}
const completedExercises = {};
for (var i = 0; i < mergedSets.length; i++) {
let set = mergedSets[i];
let exercise = exercises[set.exercise_id]
let name = exercise.exercise_name
let bodypart = exercise.bodypart
if (exerciseTypes[bodypart]) {
exerciseTypes[bodypart] += 1
} else if (!exerciseTypes[bodypart]) {
exerciseTypes[bodypart] = 1
}
if (exercise.ex_type === 'lift') {
if (!allResults[name]) {
allResults[name] = { labels: [],
datasets: [{
label: 'Weight over Time',
backgroundColor: '#2988BC',
borderColor: '#2F496E',
data: [],
}],
};
}
if (completedExercises[name] < (set.weight_lifted)) {
completedExercises[name] = set.weight_lifted
} else if (!completedExercises[name]) {
completedExercises[name] = set.weight_lifted
}
allResults[name].labels.push(allResults[name].labels.length + 1)
allResults[name].datasets[0].data.unshift(set.weight_lifted)
}
}
const PieChart = {
datasets: [{
data: Object.values(exerciseTypes),
backgroundColor: [
'#2D4262', '#363237', '#73605B', '#D09683'
],
}],
labels: Object.keys(exerciseTypes)
};
const best = Object.keys(completedExercises).map((exercise) => {
if (this.state.inputVal === '') return [];
let bests = [];
if (this.state.inputVal.length > 0) {
for (var j = 0; j < this.state.inputVal.length; j++) {
bests = [];
if (exercise.slice(0, j + 1).toUpperCase() === this.state.inputVal.slice(0, j + 1).toUpperCase()) {
bests.push(<li onClick={this.handleClick}
value={exercise}
className="best-lift-li"
key={exercise.id}>{exercise}</li>);
}
}
} else {
bests.push(<li onClick={this.handleClick}
value={exercise}
className="best-lift-li"
key={exercise.id}>{exercise}</li>)
}
return bests;
});
return (
<div>
{this.state.active === 'FIRST' ? (
<div className="best-lift-div">
<div className='best-lift-div-two'>
<h3 className="best-lift-title">Personal Records</h3>
<div className='best-lift-input-div'>
<input type="text" value={this.state.inputVal}
onChange={this.handleChange}
className="best-lift"
placeholder="Enter an Exercise"
/>
</div>
<ul className='best-lift-ul'>
{best}
</ul>
<button className='best-lift-button' onClick={this.handleSubmit}>Best Lift</button>
</div>
</div>
) : this.state.active === 'SECOND' ? (
<div className="best-lift-div">
<div className='best-lift-div-two'>
<h3 className="best-lift-title">
{this.state.name}: {completedExercises[this.state.name]}</h3>
<div className='chart-background'>
<Line width={250} height={200} data={allResults[this.state.name]}/>
</div>
<button className='best-lift-button' onClick={this.handleSubmit}>Back</button>
</div>
<div className='best-lift-div-three'>
<h3 className="best-lift-title">Workout Analysis</h3>
<div className='pie-chart-background'>
<Pie circumfrence={100} data={PieChart} />
</div>
</div>
</div>
) : null}
</div>
)
}
}
export default withRouter(SearchBestWorkouts)
import React from 'react';
import values from 'lodash/values'
import InfiniteScroll from 'react-infinite-scroll-component';
import { withRouter } from 'react-router'
class WorkoutShow extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick (e) {
e.preventDefault();
this.props.deleteWorkout(this.props.selectedWorkout).then(
() => {
this.props.requestUser(this.props.match.params.userId)
}
)
this.props.toggleParent();
}
render () {
const setArray = values(this.props.selectedWorkout.setresults)
const exercises = this.props.exercises
const results = setArray.map((result, idx) => {
if (result.workout_id === this.props.selectedWorkout.id) {
return <li key={result.id} className='workout-show-li'>
<p className='workout-title'><p>Set {idx + 1}: </p><p>{exercises[result.exercise_id].exercise_name}</p></p>
<ul>
{result.weight_lifted ? (
<li className='workout-result-li'><p className='workout-result-li'>Weight:</p>{result.weight_lifted}{result.weight_unit}</li>
) : null}
{result.reps ? (
<li className='workout-result-li'><p className='workout-result-li'>Reps:</p>{result.reps}</li>
) : null}
{result.distance ? (
<li className='workout-result-li'><p className='workout-result-li'>Distance:</p>{result.distance}{result.distance_unit}</li>
) : null}
{result.hour || result.min || result.sec ? (
<li className='workout-result-li'><p className='workout-result-li'>Duration:</p>
<div className='dur-format'>
{result.hour ? (
<p className='dur-result-hour'>{result.hour}:</p>
) : null}
{result.min ? (
<p className='dur-result'>{result.min}:</p>
) : null}
{result.sec ? (
<p className='dur-result'>{result.sec}</p>
) : null}
</div>
</li>
) : null }
</ul>
</li>
}
})
return (
<div className="workout-show-main">
<h3 className="workout-show-title">{this.props.selectedWorkout.name}
<button className='remove-workout-button' onClick={this.handleClick}>DELETE</button></h3>
<InfiniteScroll>
<ul className="workout-show-ul">
{results}
</ul>
</InfiniteScroll>
</div>
);
}
}
export default withRouter(WorkoutShow);
const setArray = values(this.props.selectedWorkout.setresults)
const exercises = this.props.exercises
const results = setArray.map((result, idx) => {
const setArray = values(this.props.selectedWorkout.setresults) || []
const exercises = this.props.exercises
const results = setArray.map((result, idx) => {