React rails rendering home page view - ruby-on-rails

I have rails API and react separate app. I can fetch data from rails view homepage in the console. how do I render it using react? My react code is as follows:
import React, { Component } from 'react';
import axios from 'axios'
class HomePage extends Component {
componentDidMount(){
axios.get('http://localhost:3001/')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
render(){
return(
<h1>{this.response}</h1>
)
}
}
export default HomePage

You could store the response in state e.g. as data and then render this.state.data.

You need to declare response globally if you want to call it like that in your render. The way you have it now, this.response isn't attached to anything. Colin hit the nail on the head -
class HomePage extends Component {
constructor(){
super();
this.state = {
heading: ''
}
}
componentDidMount(){
axios.get('http://localhost:3001/')
.then(function (response) {
this.setState({
heading: response.data
})
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
}
render(){
return(
<h1>{this.state.data}</h1>
)
}
}

Related

Ember transition.retry() not removing previous view

Creating a simple login based on Ember.js Authentication - the right way - on first access the user get's transitioned to a session login view and once validated transitioned back to the route they first tried to access all works fine except the login form remains in view after the transition and render of the views for the new route.
Setup is:
Ember : 1.7.0
Ember Data : 1.0.0-beta.8.2a68c63a
Handlebars : 1.3.0
jQuery : 1.11.1
Router:
Router.map(function() {
this.resource('sessions', function() {
this.route('logout');
this.route('login');
});
this.resource('posts', { path: '/posts' }, function() {
this.route('post', { path: '/post/:post_id' });
this.route('new');
});
});
Application route:
export default Ember.Route.extend({
beforeModel: function() {
this.transitionTo('posts');
}
});
Posts route:
export default Ember.Route.extend({
beforeModel: function(transition) {
if(Ember.isEmpty(this.controllerFor('sessions').get('token'))) {
return this.redirectToLogin(transition);
}
},
redirectToLogin: function(transition) {
this.controllerFor('sessions').set('attemptedTransition', transition);
return this.transitionTo('sessions');
},
model: function() {
return this.store.find('post');
},
actions: {
...
}
});
Sessions route:
export default Ember.Route.extend({
// Reset Session Controller to avoid date from a past authentication
setupController: function(controller, context) {
controller.reset();
}
});
Sessions controller:
export default Ember.Controller.extend({
// initialization method to verify if there is a access_token cookie set
// so we can set our ajax header with it to access the protected pages
init: function() {
Ember.Logger.log('sessons.init');
Ember.Logger.log(Ember.$);
this._super();
if (Ember.$.cookie('access_token')) {
Ember.$.ajaxSetup({
headers: {
'Authorization': 'Bearer ' + Ember.$.cookie('access_token')
}
});
}
},
// overwriting the default attemptedTransition attribute from the Ember.Controller object
attemptedTransition: null,
// create and set the token & current user objects based on the respective cookies
token: Ember.$.cookie('access_token'),
currentUser: Ember.$.cookie('auth_user'),
// create a observer binded to the token property of this controller
// to set/remove the authentication tokens
tokenChanged: function() {
Ember.Logger.log('tokenChanged');
if (Ember.isEmpty(this.get('token'))) {
Ember.$.removeCookie('access_token');
Ember.$.removeCookie('auth_user');
} else {
Ember.$.cookie('access_token', this.get('token'));
Ember.$.cookie('auth_user', this.get('currentUser'));
}
}.observes('token'),
// reset the controller properties and the ajax header
reset: function() {
this.setProperties({
username_or_email: null,
password: null,
token: null,
currentUser: null
});
Ember.$.ajaxSetup({
headers: {
'Authorization': 'Bearer none'
}
});
},
actions: {
loginUser: function() {
Ember.Logger.log('loginUser');
var _this = this;
var attemptedTrans = this.get('attemptedTransition');
var data = this.getProperties('username_or_email', 'password');
Ember.Logger.log(data);
// Clear form fields
this.setProperties({
username_or_email: null,
password: null
});
// send a POST request to the /sessions api with the form data
Ember.$.post('/api/session', data).then( function(response) {
Ember.Logger.log(response);
// set the ajax header
Ember.$.ajaxSetup({
headers: {
'Authorization': 'Bearer ' + response.api_key.access_token
}
});
// create an apiKey record on the local storage based on the returned object
var key = _this.get('store').createRecord('apikey', {
accessToken: response.api_key.access_token
});
// find a user based on the user_id returned from the request to the session api
_this.store.find('user', response.api_key.user_id).then(function(user) {
Ember.Logger.log('user->');
Ember.Logger.log(user);
// set this controller token & current user properties
// based on the data from the user and access_token
_this.setProperties({
token: response.api_key.access_token,
currentUser: user.getProperties('username')
});
// set the relationship between the User and the ApiKey models & save the apiKey object
key.set('user', user);
key.save();
user.get('api_keys').content.push(key);
Ember.Logger.log(attemptedTrans);
if(attemptedTrans) {
attemptedTrans.retry();
_this.set('attemptedTrans', null);
}
});
});
}
}
});
It's the last attemptedTrans.retry() that initiates the transition. Am I missing something?
You likely have bad html in your handlebars (missing closing tags etc).
Kingpin2k's answer above pointed me in the right direction. For anyone else stumbling across this question it boiled down to an error in my use of {{outlet}}. My original application template had the following structure:
{{#if isAuthenticated}}
<div>
... (Nav etc)
</div>
{{outlet}}
{{else}}
{{outlet}}
{{/if}}
The effect of this was that once isAuthenticated is true the template is re-rendered and the script tags used to identify the login form elements are no longer valid - hence they don't get removed.
Simple solution was to change the template to:
{{#if isAuthenticated}}
<div>
... (Nav etc)
</div>
{{/if}}
{{outlet}}

Ember template doesn't update after saving model with EmberFire adapter for Firebase

I'm using Firebase as the backend for my Ember app and successfully hooked up Firebase with EmberFire. However, when I try to save my models after creating a record, while they are posted to Firebase, they are not updated in the client's ember template.
My code for the action handler before I realized this was:
actions: {
publishPost: function() {
var newPost = this.store.createRecord('post', {
title: this.get('post.title'),
body: this.get('post.body'),
timestamp: new Date()
});
newPost.save();
}
}
And my code to try and solve this (but that doesn't work) by catching the promise returned by the save() and find() methods is:
actions: {
publishPost: function() {
var newPost = this.store.createRecord('post', {
title: this.get('post.title'),
body: this.get('post.body'),
timestamp: new Date()
});
this.store.find('post').then(function(posts) {
posts.addObject(newPost);
posts.save().then(function() {
newPost.save();
});
});
}
}
Am I just not handling the logic in the above code correctly to update the template or is there another Firebase/EmberFire compatible solution for this?
On https://github.com/broerse/ember-cli-blog-fire I did this:
import Ember from "ember";
export default Ember.ObjectController.extend({
actions: {
createPost: function() {
var newPost = this.get('store').createRecord('post');
newPost.set('date' , new Date());
newPost.set('author' , 'C.L.I. Ember');
this.get('target').transitionTo('post', newPost.save());
}
}
});
transitionTo can handle the newPost.save() promise.
Try it on: http://exmer.com/bloggrfire/posts

CORS not working with React app

I tried to make a request from wikipedia api. Though I use a normal node.js server (localhost) i get this in the console:
XMLHttpRequest cannot load https://en.wikipedia.org/w/api.php?action=query&format=json&prop=pageimages&generator=search&piprop=name|original&pilimit=max&gsrsearch=Horse&gsrlimit=20. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
This is my react component:
import React, {Component} from 'react';
import axios from 'axios';
class WikipediaViewer extends Component {
constructor(props) {
super(props);
this.state = {
data: null
}
}
componentDidMount() {
axios.get('https://en.wikipedia.org/w/api.php?action=query&format=json&prop=pageimages&generator=search&piprop=name|original&pilimit=max&gsrsearch=Horse&gsrlimit=20')
.then(data => {
this.setState({
data: data
});
console.log(data);
})
}
render() {
return (
<h1>HEllo world!</h1>
);
}
}
export default WikipediaViewer
After having issus with the request I add following config options according to the axios documentation:
componentDidMount() {
axios.get({
method: 'get',
url: 'https://en.wikipedia.org/w/api.php?action=query&format=json&prop=pageimages&generator=search&piprop=name|original&pilimit=max&gsrsearch=Horse&gsrlimit=20',
headers: {'X-Requested-With': 'XMLHttpRequest'},
withCredentials: true,
}).then(data => {
this.setState({
data: data
});
console.log(data);
})
}
Result:
GET http://localhost:3000/[object%20Object] 404 (Not Found)
Why am I have to get this error, though I'm working locally. Btw I used the "Allow-Control-Allow-Origin: *" Chrome extension from vitcad as well and it doesn't work.

How to get Accounts.onLogin to impact my app in Meteor React ES6?

I want my meteor app to call setState in App on login and logout. How can I have one section of code (ie: Accounts.onLogon) affect inside another component (ie App{})? Also, what to do to detect logouts?
Accounts.onLogin(function(user){
console.log('hi');
//App.showPrivate();
});
class App extends Component {
constructor(props) {
super(props);
this.state = {
showPublic: false,
};
}
toggleShowPublic() {
this.setState({
showPublic: !this.state.showPublic,
});
}
showPublic() {
this.setState({
showPublic: true,
});
}
showPrivate() {
this.setState({
showPublic: false,
});
}
render() {
return (
<div className="container">
<div className="show-public" onClick={this.toggleShowPublic.bind(this)}>
{this.state.showPublic ?
<span className="private-public"> View private</span> :
<span className="private-public"> View public </span>
}
</div>
</div>
);
}
}
Instead of Accounts.onLogin you should use Meteor's in-built reactive data sources to determine the user's logged-in status:
class App extends Component {
constructor(props) {
super(props);
this.state = { showPublic: false };
}
toggleShowPublic() {
this.setState({ showPublic: !this.state.showPublic });
}
render() {
return (
<div className="container">
{this.props.isLoggedIn ?
<div className="show-public" onClick={this.toggleShowPublic.bind(this)}>
{showPrivate ?
<span className="private-public"> View private</span> :
<span className="private-public"> View public </span>
}
</div> :
Show something else if the user is not logged in here...
}
</div>
);
}
}
export default createContainer(() => {
return {
isLoggedIn: !!Meteor.user()
}
}, App);
Now Meteor will take care of reactively updating this.props.isLoggedIn for you. Note that you need to install meteor/react-meteor-data and import createContainer for this to work:
import { createContainer } from 'meteor/react-meteor-data';
If you still need to do something when the user logs in, you can place Accounts.onLogin basically anywhere you want in your app, as long as you consider whether you want it to run server-side or client-side or both. For best practices regarding application structure, check out Meteor Guide.
It turns out Accounts.onLogin is a distraction. To have the app update when the user logs in or out, we need to see when the logged in user changes, and react accordingly. Seeing when something changes in React is done using componentWillReceiveProps, as seen below:
componentWillReceiveProps(nextProps) {
// user just logged in/out
if (!this.props.currentUser && nextProps.currentUser) {
this.setState({ showPublic: false });
}
}
oh, and current users comes from:
export default createContainer(() => {
return {
currentUser: Meteor.user(),
};
}, App);

Where can I put global ajax error handling in Ember?

In my application's adapter, I'm returning error codes based on ajax errors. I'm handling these in the application route's error method. This works great if I access a route via link-to. But if I refresh a route or just type the URL in, my application's error handler isn't called. Is there a place where I can put this error handling that will be guaranteed to run every time? I really don't want to implement the same "if 401, show login" code in every single route.
routes/application.js:
export default Ember.Route.extend({
actions: {
error: function(reason) {
if (reason === 401) {
alert('401');
this.send('showLogin');
}
},
adapters/application.js:
import DS from 'ember-data';
export default DS.ActiveModelAdapter.extend({
'namespace': '',
ajaxError: function(jqXHR) {
var error = this._super(jqXHR);
if (jqXHR && jqXHR.status === 401) {
return 401;
}
return error;
}
});
Edit:
The above code nearly worked for me. The main issue I hit was this.send('showLogin') wasn't being caught when refreshing or hitting the URL. Changing this to a transitionTo works great:
import Ember from 'ember';
export default Ember.Route.extend(ApplicationRouteMixin, {
actions: {
error: function(reason) {
if (reason === 401) {
this.transitionTo('login');
}
},
...
You can make an application adapter, and then extend every adapter from this, and use isInvalid function.
//app/adapters/application.js
import DS from 'ember-data';
import Ember from 'ember';
export default DS.JSONAPIAdapter.extend({
isInvalid(status, headers, payload){
if (status===401) {}
},
});
//app/adapters/anotherAdapter.js
import AppAdapter from 'yourapp/adapters/application';
export default AppAdapter.extend({
});
If you're using RSVP promises, then
Ember.RSVP.on('error', function(error) {
// ...
});
Or if you're using plain jQuery xhr
$(document).ajaxError(function(evt, jqXHR) {
// ...
});

Resources