Skip to content

Instantly share code, notes, and snippets.

@jennceng
Last active January 11, 2017 22:25
Show Gist options
  • Save jennceng/354787a14acfc14b9c4ca6d24f3c4710 to your computer and use it in GitHub Desktop.
Save jennceng/354787a14acfc14b9c4ca6d24f3c4710 to your computer and use it in GitHub Desktop.

Rails Asset Pipeline

Main Points

  • a lot of the reading is just explanations for what is already there with Rails, such as the manifest files which gives instructions to sprockets as to what assets you wish to be served from your app
  • essentially this is how Rails takes all of your various javascripty cssy things and precompiles it all into one large js asset and one large cs asset so you can serve it up to your web app
  • part of the main takeaway is when things are going great we barely concern ourselves with the asset pipeline, but it often becomes necessary to look at when we’re troubleshooting a bug so it’s good to know how to navigate the pipeline
  • for example for the Tablesorter plugin, they would likely get unexpected behavior if they tried to require jquery.tablesorter before requiring jquery since it depends on the jquery library

Asset Pipeline

  • static assets - CSS and JavaScript don’t need to be generated dynamically, they don’t chagnes as we add new info
  • In our app we may have many many js files, css files, etc.
  • the Asset Pipeline (assembled via **sprockets **gem) consolidate those into one large js file and one large css file that leads to a faster / better UI experience

Linking External Assets

  • one method is to store them as external fields and reference them using <link> or <script> tags
  • when a broswer loads this HTML, it scans for these tags and will send additional HTTP requests to fetch the external stylesheets and JavaScript source files
  • this extra request has a bit of overhead, but browser can **cache **them and reuse them between pages, saving them locally for a period of time

Pre-compiling Assets

  • For production assets must be pre-compiled
  • Heroku does this for you, so if you’re deploying to heroku don’t pre-compile your assets! If you do, see the following fix
  • If you make changes in development in regards to js/css and push to production, but don’t see those changes, or perhaps not seeing changes even locally in your brower, it may be because you attempted to pre-compile your assets. To solve this on the command line, it’s clobberin time
rake assets:clobber

Adding React to Rails

This is largely just a walk through, a few things that can be pointed out are especially the .babelrc and the webpack.config.js

// webpack.config.js
var config = {
  entry: {
    // source of the react code
    path: './react/src/main.js',
  },
  output: {
    // this is where it will go into our Rails asset Pipeline
    path: './app/assets/javascripts',
    filename: 'bundle.js'
  },
  ...
}
...

Add the node modules, bundle.js, and coverage to gitignore because those files are big AF

Remind them they won’t be doing this manually all the time, from now on if they know they want React from the get-go they should just make a boilerplate to work from for future projects

Development and Deployment

  • not that they have reployed to heroku yet, but when they do remind them they will need to run those commands when deploying to heroku

Ajax in a React Application within Rails

Pretty straightforward, guide them through what’s going on in the Api::FortunesController

$ curl localhost:3000/api/fortune

to reiterate human vs. machine endpoints / interfaces

They may be a bit rusty on React so just walk them through what’s happening, perhaps putting a debugger in the asynch call:

import React, { Component } from 'react';

class Fortune extends Component {
  constructor(props) {
    super(props);
    this.state = { fortune: '' };
  }

  componentDidMount() {
    // remind them of lifecycle methods, waiting for the component to mount before going to asynchronously fetch some info
    $.ajax({
      url: '/api/fortune',
      contentType: 'application/json'
    })
    .done(data => {
      // this sets the state of the Fortune component to the response data
      this.setState({ fortune: data.fortune });
    });
  }

  render() {
    return (
      <h1>Your Fortune: {this.state.fortune}</h1>
    );
  }
}

export default Fortune;

Alternate Fetch syntax:

import React, { Component } from 'react';

class Fortune extends Component {
  constructor(props) {
    super(props);
    this.state = { fortune: '' };
  }

  componentDidMount() {
    fetch('/api/fortune.json')
      // don't actually need to specify the format since the api endpoint only really does one thing, but watevs
      .then(response => {
        let { ok, status, statusText } = response;
        if (ok) {
          return response.json();
        } else {
          let error = new Error(`getUser: ${status} (${statusText})`);
          throw(error);
        }
      })
      .then(data => {
        this.setState({fortune: data.fortune})
      });
  }

  render() {
    return (
      <h1>Your Fortune: {this.state.fortune}</h1>
    );
  }
}

export default Fortune;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment