Tagged: rails 6 Toggle Comment Threads | Keyboard Shortcuts

  • kmitov 5:41 am on October 6, 2020 Permalink |
    Tags: , progressive web application, pwa, , rails 6,   

    The path to a progressive web app – or how we skipped the whole JS Frameworks on the client thing. 

    I recently responded to a question in the Stimulus JS forum that prompted me to write this blog.

    About 6 months ago we decided to skip the whole “JSON response from server and JS framework on the client” stuff and we’ve never felt better. We significantly reduce the code base while delivering more features. We manage to do it with much less resources. Here is an outline of our path

    Progressive Web Application

    We had a few problems.

    1. Specs that were way to fragile and user experience that was way to fragile. Fragile specs that are failing from time to time are not a problem on their own. They are an indicator that the features also do not work in the client browsers from time to time.
    2. Too much and two difficult JS on the client. Although it might see that making a JSON request from the client to the server and generating the HTML from the response might seem as a good idea, it is not always a good idea. If we are to generate the HTML from a JSON, why don’t we ask the server for the HTML and be done with it? Yes, some would say it is faster, but we found out it is basically the same for the server to render ‘{“video_src”: “https://…&#8221;}’ or to render “<video src=’https://…&#8217;></video>’ . The drawback is that in the first scenario you must generate the video tag on the client and this means more work. Like twice the amount of work.

    So we said:

    Let’s deliver the platform to a browser that has NO JS at all, and if it has, we would enhance it here and there.

    How it worked out?

    In retrospective… best decision even. Just know that there is not JS in the browser and try to deliver your features. Specs got a lot faster and better. 1h 40 m compared to 31 minutes. They are not fragile. We have very little JS. The whole platform is much faster. We user one framework less. So, I see no drawbacks.

    First we made the decision not to have a JS framework on the client and to drop this idea as a whole. For our case it was just adding complexity and one more framework. This does not happen overnight, but it could happen. So we decide that there is no JS and the whole platform should work in the case of JS disabled on the browser (this bootstrap navigation menus are a pain in the a…). It should be a progressive web application (PWA).

    After this decisions we did not replace JSON with Ajax calls. We skipped most of them entirely. Some JSON requests could not be skipped, but we changed them as AJAX – for example “generating a username”. When users register they could choose a username, but to make it easier for them we generate one by default. When generating we must make sure it is a username that does not exists in the DB. For this we need to make a request to the server and this is one place we are using Stimulus to submit the username.

    A place that we still use JSON is with Datatables- it is just so convenient. There are also a few progress bars that are making some legacy JSON requests.

    Overall we have Ajax here and there, an a few JSON requests, but that’s it. Like 90-95% of the workflow is working with JS disabled.

    We even took this to the extreme. We are testing it with browsers with JS and browsers without JS. So a delete button on a browser without JS is not opening a confirmation. But with JS enabled the delete opens a confirmation. I was afraid this will introduce a lot of logic in the specs, but I am still surprised it did not. We have one method “js_agnostic_delete” with an if statement that check if JS is enabled and decides what to do.

    My point is that moving JSON to Ajax 1:1 was not for us. It would not pay off as we would basically be doing the same, but in another format. What really payed off and allowed us to reduce the code base with like 30-40%, increase the speed and make the specs not so fragile was to say – “let’s deliver our platform to a JS disabled browser, and if it has JS, than great.”

    To give you even more context this was a set of decisions we made in April 2020 after years of getting tired with JS on client. We are also quite experience with JS as we’ve build a pretty large framework for 3D that is running entirely in browser so it was not like a lack of knowledge and experience with JS on our side that brought us to these decisions. I think whole team grew up enough to finally do without JS.

     
  • kmitov 5:23 pm on May 21, 2020 Permalink |
    Tags: , , , , rails 6, , ,   

    With assets in a rails engine it could be Gemfile vs gemspec dependency that is messing it up 

    You have a rails engine. It has an asset (like a scss file). You include this engine in another engine. How do you test that the assets is correctly resolved?

    There is a moment when you simply can not understand where and how the asset is resolved/not resolved. The solution actually is in what are the Gemfile and .gemspec for a rails engine. Both of them could describe dependencies, but they contain different things.

    The whole premise of the situation seems strange until you get to building a rails engine that would contain the “theme” of your app. We go in this situation with two of our platforms – FLLCasts.com and 3DAssemblyInstructions.com. We wanted to have different layouts in different gems that are providing different look an feel- separate the main layout from dashboard and from main. We also wanted to have this layouts in a different gems so that we could release them with different versions and test them as separate gems in separate builds.

    Let’s get into this step by step tutorial and by the end I am sure you would know much about how assets are resolved, packed and testes when they are within a rails. Again I am writing this tutorial to help spread the knowledge internally, but the problem is so common that it might be of interest to the community as a whole.

    Case 1 – simple app with an asset

    Just to get the understanding correctly and to have a base we would create a simple rails app with an asset and start it. I am using rails 6 and ruby 2.6.5

    $ rails new simple_assets_app
    $ cd simple_asset_app
    # Create a new asset.scss file with some content
    $ echo "asset_style { background-color: white}" > app/assets/stylesheets/asset.scss
    $ rails s
    => Booting Puma
    => Rails 6.0.3.1 application starting in development 
    => Run `rails server --help` for more startup options
    Puma starting in single mode...
    * Version 4.3.5 (ruby 2.6.5-p114), codename: Mysterious Traveller
    * Min threads: 5, max threads: 5
    * Environment: development
    * Listening on tcp://127.0.0.1:3000
    * Listening on tcp://[::1]:3000
    Use Ctrl-C to stop
    
    

    In another terminal request the asset

    # Request the asset and dislay its content. Everything works. Perfect
    $ curl localhost:3000/assets/asset.scss
    asset_style { background-color: white}

    Case 2 – engine with an asset

    Now let’s build a rails plugin that would hold this asset

    $ rails plugin new simple_asset_engine --full
    $ cd simple_asset_engine/
    $ echo "asset_style { background-color: white}" > app/assets/stylesheets/asset.scss
    # You have to fix the TODOs in the gemspec. After you are ready do 
    $ rails s -p 3001
    => Booting WEBrick
    => Rails 6.0.3.1 application starting in development http://localhost:3001
    => Run `rails server --help` for more startup options
    [2020-05-21 19:48:51] INFO  WEBrick 1.4.2
    [2020-05-21 19:48:51] INFO  ruby 2.6.5 (2019-10-01) [x86_64-linux]
    [2020-05-21 19:48:51] INFO  WEBrick::HTTPServer#start: pid=13394 port=3001
    

    Now that the port is different.

    Request the asset

    # Nothing strange here. Asset is delivered as expected.
    $ curl localhost:3001/assets/asset.scss
    asset_style { background-color: white}
    

    Conclusion – engine, no engine the asset is delivered.

    Case 3 – require simple_asset_engine in another engine

    This could be a requirement. It has happen to us. It is a valid case. It is rather strange to have one engine require another, but we are all grown ups here…

    $ rails plugin new host_engine --full
    # Fix todos in .gemspec
    
    # Add a dependency to simple_asset_engine. Asset should be found, rigth
    $ echo 'gem "simple_asset_engine", path: "~/axles/tmp/simple_asset_engine"' >> Gemfile
    
    # install gems - mainly the simple_asset_engine
    $ bundle install
    
    # Start server. Note the different port
    $ rails s -p 4010
    
    

    Request asset

    $ curl localhost:4010/assets/asset.scss
    asset_style { background-color: white}

    Asset is found.

    That’s the power of rails. It just works. You can have an asset in an app, asset in an engine, asset in an engine, required in another engine and the asset is always found. Except…

    This might sound as a conclusion, because everything works. Until you get to production, which is actually the only time it matters if anything works, but that’s another story.

    Our current host_engine depends on a gem with a local path in the local filesystem.

    host_engine: $ cat Gemfile
    source 'https://rubygems.org'
    git_source(:github) { |repo| "https://github.com/#{repo}.git" }
    
    # Declare your gem's dependencies in host_engine.gemspec.
    # Bundler will treat runtime dependencies like base dependencies, and
    # development dependencies will be added by default to the :development group.
    gemspec
    
    # Declare any dependencies that are still in development here instead of in
    # your gemspec. These might include edge Rails or gems from your path or
    # Git. Remember to move these dependencies to your gemspec before releasing
    # your gem to rubygems.org.
    
    # To use a debugger
    # gem 'byebug', group: [:development, :test]
    gem "simple_asset_engine", path: "~/axles/tmp/simple_asset_engine"

    This is something that we can not ship to production. That’s why we pack “simple_asset_engine” as a gem and place this gem in a gemrepo. This is not part of the tutorial so I will simulate it.

    We should also modify the host_engine.gemspec to depend on simple_asset_engine. We add a dependency.

    # in host_engine.gemspec we add
    
    spec.add_dependency "simple_asset_engine"
    

    This means – ‘add a dependency to “simple_asset_engine”‘. Our gem will host_engine will depend on ‘simple_asset_engine’, but and here is a but, but only for ‘production’ environment. So this means – “production”. To simulate the fact that we don’t have this gem in a repo we would change the dependency in the Gemfile to be only for production.

    # This means the same as spec.add_dependency 'simple_asset_engine' It add the gem as a dependency to production. We are doing it like this to simulate that we have 'spec.add_dependency' and the gem is coming from a gems repo
    
    gem "simple_asset_engine", group: [:production], path: "~/axles/tmp/simple_asset_engine"

    Now as you do request the asset a strange error occurs:

    $ curl localhost:4010/assets/asset.scss
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8" />
      <title>Action Controller: Exception caught</title>
        ....
       <div id="Framework-Trace-0" style="display: none;">
          <code style="font-size: 11px;">
              <a class="trace-frames trace-frames-0" data-exception-object-id="47236752082100" data-frame-id="0" href="#">
                actionpack (6.0.3.1) lib/action_dispatch/middleware/debug_exceptions.rb:36:in `call'
              </a>
              <br>
              <a class="trace-frames trace-frames-0" data-exception-object-id="47236752082100" data-frame-id="1" href="#">
                actionpack (6.0.3.1) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
              </a>
              <br>
              <a class="trace-frames trace-frames-0" data-exception-object-id="47236752082100" data-frame-id="2" href="#">
                railties (6.0.3.1) lib/rails/rack/logger.rb:37:in `call_app'
              </a>
    ...
    </div>
    </body>
    </html>
    

    In the log you see

    ActionController::RoutingError (No route matches [GET] "/assets/asset.scss"):
      
    actionpack (6.0.3.1) lib/action_dispatch/middleware/debug_exceptions.rb:36:in `call'
    actionpack (6.0.3.1) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
    railties (6.0.3.1) lib/rails/rack/logger.rb:37:in `call_app'
    railties (6.0.3.1) lib/rails/rack/logger.rb:26:in `block in call'
    activesupport (6.0.3.1) lib/active_support/tagged_logging.rb:80:in `block in tagged'
    activesupport (6.0.3.1) lib/active_support/tagged_logging.rb:28:in `tagged'
    activesupport (6.0.3.1) lib/active_support/tagged_logging.rb:80:in `tagged'
    railties (6.0.3.1) lib/rails/rack/logger.rb:26:in `call'
    sprockets-rails (3.2.1) lib/sprockets/rails/quiet_assets.rb:11:in `block in call'
    activesupport (6.0.3.1) lib/active_support/logger_silence.rb:36:in `silence'
    activesupport (6.0.3.1) lib/active_support/logger.rb:64:in `block (3 levels) in broadcast'
    activesupport (6.0.3.1) lib/active_support/logger_silence.rb:36:in `silence'
    activesupport (6.0.3.1) lib/active_support/logger.rb:62:in `block (2 levels) in broadcast'
    sprockets-rails (3.2.1) lib/sprockets/rails/quiet_assets.rb:11:in `call'
    actionpack (6.0.3.1) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
    actionpack (6.0.3.1) lib/action_dispatch/middleware/request_id.rb:27:in `call'
    rack (2.2.2) lib/rack/method_override.rb:24:in `call'
    rack (2.2.2) lib/rack/runtime.rb:22:in `call'
    activesupport (6.0.3.1) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
    actionpack (6.0.3.1) lib/action_dispatch/middleware/executor.rb:14:in `call'
    actionpack (6.0.3.1) lib/action_dispatch/middleware/static.rb:126:in `call'
    rack (2.2.2) lib/rack/sendfile.rb:110:in `call'
    actionpack (6.0.3.1) lib/action_dispatch/middleware/host_authorization.rb:82:in `call'
    railties (6.0.3.1) lib/rails/engine.rb:527:in `call'
    rack (2.2.2) lib/rack/handler/webrick.rb:95:in `service'
    

    It is basically telling us that an error occurred. An error also should occur. It is logical, it is the right thing to do, but it can take hours to debug and understand this.

    The error occurs because we are starting the rails server in ‘development’ environment and the dependency to ‘simple_asset_engine’ is only for production.

    Case 3.1 – change to production and development

    # Change host_engine/Gemfile to have
    
    gem "simple_asset_engine", group: [:production, :development], path: "~/axles/tmp/simple_asset_engine"
    

    Restart server on port 4010.

    host_engine: $ rails s -p 4010
    => Booting WEBrick
    => Rails 6.0.3.1 application starting in development http://localhost:4010
    => Run `rails server --help` for more startup options
    [2020-05-21 20:14:55] INFO  WEBrick 1.4.2
    [2020-05-21 20:14:55] INFO  ruby 2.6.5 (2019-10-01) [x86_64-linux]
    [2020-05-21 20:14:55] INFO  WEBrick::HTTPServer#start: pid=14167 port=4010

    Request the asset

    $ curl localhost:4010/assets/asset.scss
    asset_style { background-color: white}

    Now it is time for conclusion

    spec.add_dependency in a gemspec gives you a dependency for production. There is a ‘spec.add_development_dependency’ that exists, but there are great discussion about it here https://github.com/rubygems/rubygems/issues/1104 Read more there. Really. Read more.

    But as we are trying to test assets separately in an engine it is important to understand what Gemfile and gemspec could be used for. If an asset is not found from a dependency of a gemspec, probably the whole dependency is required for a different environment. In the same time if the dependency contains only assets, it might be difficult to get what is happening at first sight and is it your fault, or that the F..k is sprockets doing or event what the bigger f..k is webpacker doing. But for this case it is just plain old ruby dependencies that are messing us up.

     
  • kmitov 1:03 pm on April 22, 2020 Permalink |
    Tags: , , , rails 6, , ,   

    Rails 6 + webpacker + jquery + sprockets + jquery plugin (fancetree) 

    So you might be in the process of migrating to webpacker. This means your sprockets should continue working. This is difficult. Sprockets wants jquery available in the view and you don’t have jquery available in the views. You have it in the webpacker packs.

    These things won’t work

      <script> 
        $("element_id")
      </script>

    jQuery is only available to the PACKS it is not available to the VIEWS.

    But there is a solution – expose-loader

    Here is how to setup jquery to be available to the views in sprockets app that you are migrating to rails 6. I am starting from the previous article were we set up the project from 0. – https://kmitov.com/posts/rails-6-webpacker-yarn-fancytree-less/

    $ yarn add expose-loader

    Add configuration for exposing of jquery

    // config/webpack/environments.js
    const { environment } = require('@rails/webpacker')
     
    const less_loader= {
     test: /\.less$/,
     use: ['css-loader', 'less-loader']
    };
    environment.loaders.append('less', less_loader)
    
    +
    +const webpack = require('webpack')
    +// this makes jquery available in all pack and you don't
    +// have to import or require it each time 
    +environment.plugins.prepend(
    +  'Provide',
    +  new webpack.ProvidePlugin({
    +    $: 'jquery',
    +    jQuery: 'jquery'
    +  })
    +)
    +
    +// this exposes jquery to be available in the views
    +// <script>
    +//   console.log($('#tree'))
    +// </script>
    +environment.loaders.append('expose', {
    +  test: require.resolve('jquery'),
    +  use: [{
    +    loader: 'expose-loader',
    +    options: '$'
    +  }, {
    +    loader: 'expose-loader',
    +    options: 'jQuery',
    +  }]
    +})

    Also expose fancytree

    // config/webpack/environments.js
    ...
    +// this exposes fancytree to be available in the views
    +// <script>
    +//   console.log($('#tree').fancytree())
    +// </script>
    +environment.loaders.append('fancytree', {
    +  test: require.resolve('jquery.fancytree'),
    +  use: [{
    +    loader: 'expose-loader',
    +    options: 'fancytree'
    +  }]
    +})
    

    And you are done.

    How in your views you could do:

    <script>
      console.log($('#tree'))
      $(function(){
        $('#tree').fancytree({
          extensions: ['edit', 'filter'],
          source: [
            {title: "Node 1", key: "1"},
            {title: "Folder 2", key: "2", folder: true, children: [
              {title: "Node 2.1", key: "3"},
              {title: "Node 2.2", key: "4"}
            ]}
          ],
        });
        const tree = fancytree.getTree('#tree');
        // Note: Loading and initialization may be asynchronous, so the nodes may not be accessible yet.
      })
    </script>
    

    Fancytree as a jquery plugin is working in rails 6 views and is available also to sprockets compiled files.

     
  • kmitov 8:45 am on April 22, 2020 Permalink |
    Tags: css, , less, npm, , rails 6, , , yarn   

    Rails 6 + webpacker + yarn + Fancytree + LESS 

    We had to migrate a gem from using fancytree-rails as a ruby gem to a new rails 6 gem using webpacker and jquery.fancytree coming from npm. On top of that jquery.fancytree is using LESS (CSS) and you have to do a few configurations.

    App is available at https://github.com/thebravoman/rails6_webpacker_fancytree_less

    Here is how to do it it a few simple commands

    Table of contents

    Create a new rails project

    We want to have Fancrytree in this project.

       $ rails new project_with_less_and_fancytree
       $ cd project_with_less_and_fancytree
       $ rails g scaffold books
       $ rails db:migrate
     

    Add fancytree yarn package

    $ yarn add jquery.fancytree
       yarn add v1.22.4
       [1/4] Resolving packages...
       [2/4] Fetching packages...
       info fsevents@1.2.12: The platform "linux" is incompatible with this module.
       info "fsevents@1.2.12" is an optional dependency and failed compatibility check. Excluding it from installation.
       [3/4] Linking dependencies...
       warning " > webpack-dev-server@3.10.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
       warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0".
       warning " > jquery.fancytree@2.35.0" has unmet peer dependency "jquery@>=1.9".
       [4/4] Building fresh packages...
       success Saved lockfile.
       success Saved 1 new dependency.
       info Direct dependencies
       └─ jquery.fancytree@2.35.0
       info All dependencies
       └─ jquery.fancytree@2.35.0
       Done in 3.29s.

    I like yarn.

    Add less and less-loader

    Later to include fancytree we would have to do things like

    import 'jquery.fancytree/dist/skin-lion/ui.fancytree.less'

    This means fancytree uses LESS. So we need to process this .less files. Oh, css, oh you evil you.

    yarn add less

    $ yarn add less
       yarn add v1.22.4
       [1/4] Resolving packages...
       warning less > request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
       [2/4] Fetching packages...
       info fsevents@1.2.12: The platform "linux" is incompatible with this module.
       info "fsevents@1.2.12" is an optional dependency and failed compatibility check. Excluding it from installation.
       [3/4] Linking dependencies...
       warning " > jquery.fancytree@2.35.0" has unmet peer dependency "jquery@>=1.9".
       warning " > less-loader@5.0.0" has unmet peer dependency "webpack@^2.0.0 || ^3.0.0 || ^4.0.0".
       warning " > webpack-dev-server@3.10.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
       warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0".
       [4/4] Building fresh packages...
       success Saved lockfile.
       success Saved 4 new dependencies.
       info Direct dependencies
       └─ less@3.11.1
       info All dependencies
       ├─ asap@2.0.6
       ├─ image-size@0.5.5
       ├─ less@3.11.1
       └─ promise@7.3.1
       Done in 5.80s.

    yarn add less-loader

    You need less and less-loader

    $ yarn add less-loader
       yarn add v1.22.4
       [1/4] Resolving packages...
       [2/4] Fetching packages...
       info fsevents@1.2.12: The platform "linux" is incompatible with this module.
       info "fsevents@1.2.12" is an optional dependency and failed compatibility check. Excluding it from installation.
       [3/4] Linking dependencies...
       warning " > jquery.fancytree@2.35.0" has unmet peer dependency "jquery@>=1.9".
       warning " > webpack-dev-server@3.10.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
       warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0".
       warning " > less-loader@5.0.0" has unmet peer dependency "less@^2.3.1 || ^3.0.0".
       warning " > less-loader@5.0.0" has unmet peer dependency "webpack@^2.0.0 || ^3.0.0 || ^4.0.0".
       [4/4] Building fresh packages...
       success Saved lockfile.
       success Saved 2 new dependencies.
       info Direct dependencies
       └─ less-loader@5.0.0
       info All dependencies
       ├─ clone@2.1.2
       └─ less-loader@5.0.0
       Done in 3.26s.
     

    Add less-loader to webpack environment

    They must be registered. Probably in another file, but here in enrovonments.js is fine this tutorial.

    // config/webpack/environments.js
    
    const { environment } = require('@rails/webpacker')
    
    // THIS IS THE NEW CODE
    const less_loader= {
      test: /\.less$/,
      use: ['css-loader', 'less-loader']
    };
    environment.loaders.append('less', less_loader)
    // END: THIS IS THE NEW CODE
    
    module.exports = environment

    Use fancytree

    Check out the documentation at https://github.com/mar10/fancytree/wiki#use-a-module-loader

    But basically you must require fancytree and use it.

    // NOTE: This seems to be working
    // app/javascripts/packs/application.js
    
    //... some other code.
    
    // THIS IS THE NEW CODE ADDED AT THE BOTTOM OF application.js
    // Import LESS or CSS:
    import 'jquery.fancytree/dist/skin-lion/ui.fancytree.less'
    
    const $ = require('jquery');
    
    const fancytree = require('jquery.fancytree');
    require('jquery.fancytree/dist/modules/jquery.fancytree.edit');
    require('jquery.fancytree/dist/modules/jquery.fancytree.filter');
    
    console.log(fancytree.version);
    
    $(function(){
      $('#tree').fancytree({
        extensions: ['edit', 'filter'],
        source: [
          {title: "Node 1", key: "1"},
          {title: "Folder 2", key: "2", folder: true, children: [
            {title: "Node 2.1", key: "3"},
            {title: "Node 2.2", key: "4"}
          ]}
        ],
      });
      const tree = fancytree.getTree('#tree');
      // Note: Loading and initialization may be asynchronous, so the nodes may not be accessible yet.
    })
    // END: THIS IS THE NEW CODE ADDED AT THE BOTTOM OF application.js

    NOTE – import is kind of not working

    There is another configuration at https://github.com/mar10/fancytree/wiki#use-a-module-loader but I could not make it work

    // NOTE: This is not working
    import 'jquery.fancytree/dist/skin-lion/ui.fancytree.less';  // CSS or LESS
    import {createTree} from 'jquery.fancytree';
    import 'jquery.fancytree/dist/modules/jquery.fancytree.edit';
    import 'jquery.fancytree/dist/modules/jquery.fancytree.filter';
    
    const tree = createTree('#tree', {
      extensions: ['edit', 'filter'],
      source: [
          {title: "Node 1", key: "1"},
          {title: "Folder 2", key: "2", folder: true, children: [
            {title: "Node 2.1", key: "3"},
            {title: "Node 2.2", key: "4"}
          ]}
        ],
    });
    // Note: Loading and initialization may be asynchronous, so the nodes may not be accessible yet.

    Start the application

    $ rails s
    => Booting Puma
    => Rails 6.0.2.2 application starting in development 
    => Run `rails server --help` for more startup options
    Puma starting in single mode...
    * Version 4.3.3 (ruby 2.6.5-p114), codename: Mysterious Traveller
    * Min threads: 5, max threads: 5
    * Environment: development
    * Listening on tcp://127.0.0.1:3000
    * Listening on tcp://[::1]:3000
    Use Ctrl-C to stop
    Started GET "/" for ::1 at 2020-04-22 09:20:06 +0300
       (0.4ms)  SELECT sqlite_version(*)
       (0.2ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
    Processing by Rails::WelcomeController#index as HTML
      Rendering /home/user/.rvm/gems/ruby-2.6.5/gems/railties-6.0.2.2/lib/rails/templates/rails/welcome/index.html.erb
      Rendered /home/user/.rvm/gems/ruby-2.6.5/gems/railties-6.0.2.2/lib/rails/templates/rails/welcome/index.html.erb (Duration: 17.4ms | Allocations: 471)
    Completed 200 OK in 45ms (Views: 25.4ms | ActiveRecord: 0.0ms | Allocations: 2931)
    
    
    Started GET "/books" for ::1 at 2020-04-22 09:20:09 +0300
    Processing by BooksController#index as HTML
      Rendering books/index.html.erb within layouts/application
      Book Load (0.2ms)  SELECT "books".* FROM "books"
      ↳ app/views/books/index.html.erb:13
      Rendered books/index.html.erb within layouts/application (Duration: 29.0ms | Allocations: 1230)
    [Webpacker] Compiling...
    [Webpacker] Compiled all packs in /home/user/axles/tmp/project_with_less_and_fancytree/public/packs
    [Webpacker] Hash: 32e57f147dbdcbbf0c82
    Version: webpack 4.43.0
    Time: 2269ms
    Built at: 04/22/2020 9:20:13 AM
                                         Asset       Size       Chunks                         Chunk Names
        js/application-bbe9c4a129ab949e0636.js    124 KiB  application  [emitted] [immutable]  application
    js/application-bbe9c4a129ab949e0636.js.map    139 KiB  application  [emitted] [dev]        application
                                 manifest.json  364 bytes               [emitted]              
    Entrypoint application = js/application-bbe9c4a129ab949e0636.js js/application-bbe9c4a129ab949e0636.js.map
    [./app/javascript/channels sync recursive _channel\.js$] ./app/javascript/channels sync _channel\.js$ 160 bytes {application} [built]
    [./app/javascript/channels/index.js] 211 bytes {application} [built]
    [./app/javascript/packs/application.js] 749 bytes {application} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 552 bytes {application} [built]
        + 3 hidden modules
    
    Completed 200 OK in 3998ms (Views: 3994.1ms | ActiveRecord: 0.7ms | Allocations: 23364)
    

    Open /books

    Visit http://localhost:3000/books. You should see no books

    Started GET "/books" for ::1 at 2020-04-22 09:23:56 +0300
    Processing by BooksController#index as HTML
      Rendering books/index.html.erb within layouts/application
      Book Load (0.2ms)  SELECT "books".* FROM "books"
      ↳ app/views/books/index.html.erb:13
      Rendered books/index.html.erb within layouts/application (Duration: 1.7ms | Allocations: 633)
    [Webpacker] Compiling...
    [Webpacker] Compilation failed:
    Hash: 60e4cd172f04061a66be
    Version: webpack 4.43.0
    Time: 4365ms
    Built at: 04/22/2020 9:24:02 AM
                                         Asset       Size       Chunks                         Chunk Names
        js/application-6ffd14b1620a1ad7ff96.js    717 KiB  application  [emitted] [immutable]  application
    js/application-6ffd14b1620a1ad7ff96.js.map    841 KiB  application  [emitted] [dev]        application
                                 manifest.json  364 bytes               [emitted]              
    Entrypoint application = js/application-6ffd14b1620a1ad7ff96.js js/application-6ffd14b1620a1ad7ff96.js.map
    [./app/javascript/channels sync recursive _channel\.js$] ./app/javascript/channels sync _channel\.js$ 160 bytes {application} [built]
    [./app/javascript/channels/index.js] 211 bytes {application} [built]
    [./app/javascript/packs/application.js] 1.52 KiB {application} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 552 bytes {application} [built]
        + 9 hidden modules
    

    Change books.html.erb

    Add a div element with id=tree

    Books

    <%# app/vies/books/index.html.erb %>
    <p id="notice"><%= notice %></p>
    
    <!-- THIS HERE IS WHAT WE ARE ADDING -->
    
    <div id="tree"></div>
    
    <!-- END: THIS HERE IS WHAT WE ARE ADDING -->
    
    <h1>Books</h1>
    
    <table>
      <thead>
        <tr>
          <th colspan="3"></th>
        </tr>
      </thead>
    
      <tbody>
        <% @books.each do |book| %>
          <tr>
            <td><%= link_to 'Show', book %></td>
            <td><%= link_to 'Edit', edit_book_path(book) %></td>
            <td><%= link_to 'Destroy', book, method: :delete, data: { confirm: 'Are you sure?' } %></td>
          </tr>
        <% end %>
      </tbody>
    </table>

    Final picture

    Showing how books index works with fancytree

    Errors that might occur

    No less-loader

    If no less loader is available the following could occur.

    Started GET "/books" for ::1 at 2020-04-22 08:52:40 +0300
       (0.1ms)  SELECT sqlite_version(*)
    Processing by BooksController#index as HTML
      Rendering books/index.html.erb within layouts/application
      Book Load (0.2ms)  SELECT "books".* FROM "books"
      ↳ app/views/books/index.html.erb:13
      Rendered books/index.html.erb within layouts/application (Duration: 2.1ms | Allocations: 762)
    [Webpacker] Compiling...
    [Webpacker] Compilation failed:
    Hash: 6210a48eff6aa0097a4c
    Version: webpack 4.43.0
    Time: 1464ms
    Built at: 04/22/2020 8:52:43 AM
                                         Asset       Size       Chunks                         Chunk Names
        js/application-8dcd2b9e8cc222d43650.js    718 KiB  application  [emitted] [immutable]  application
    js/application-8dcd2b9e8cc222d43650.js.map    841 KiB  application  [emitted] [dev]        application
                                 manifest.json  364 bytes               [emitted]              
    Entrypoint application = js/application-8dcd2b9e8cc222d43650.js js/application-8dcd2b9e8cc222d43650.js.map
    [./app/javascript/channels sync recursive _channel\.js$] ./app/javascript/channels sync _channel\.js$ 160 bytes {application} [built]
    [./app/javascript/channels/index.js] 211 bytes {application} [built]
    [./app/javascript/packs/application.js] 1.07 KiB {application} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 552 bytes {application} [built]
        + 9 hidden modules
    
    ERROR in ./node_modules/jquery.fancytree/dist/skin-lion/ui.fancytree.less 28:0
    Module parse failed: Unexpected token (28:0)
    File was processed with these loaders:
     * ./node_modules/less-loader/dist/cjs.js
    You may need an additional loader to handle the result of these loaders.
    |  * Helpers
    |  *----------------------------------------------------------------------------*/
    > .fancytree-helper-hidden {
    |   display: none;
    | }
     @ ./app/javascript/packs/application.js 19:0-59
    

    no less available

    If less was not installed this would happen

    Started GET "/books" for ::1 at 2020-04-22 09:26:54 +0300
    Processing by BooksController#index as HTML
      Rendering books/index.html.erb within layouts/application
      Book Load (0.1ms)  SELECT "books".* FROM "books"
      ↳ app/views/books/index.html.erb:13
      Rendered books/index.html.erb within layouts/application (Duration: 2.1ms | Allocations: 617)
    [Webpacker] Compiling...
    [Webpacker] Compilation failed:
    Hash: 1adef07918f113c9c28e
    Version: webpack 4.43.0
    Time: 1380ms
    Built at: 04/22/2020 9:26:56 AM
                                         Asset       Size       Chunks                         Chunk Names
        js/application-b032c274e5b1d8d383da.js    721 KiB  application  [emitted] [immutable]  application
    js/application-b032c274e5b1d8d383da.js.map    841 KiB  application  [emitted] [dev]        application
                                 manifest.json  364 bytes               [emitted]              
    Entrypoint application = js/application-b032c274e5b1d8d383da.js js/application-b032c274e5b1d8d383da.js.map
    [./app/javascript/channels sync recursive _channel\.js$] ./app/javascript/channels sync _channel\.js$ 160 bytes {application} [built]
    [./app/javascript/channels/index.js] 211 bytes {application} [built]
    [./app/javascript/packs/application.js] 1.52 KiB {application} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 552 bytes {application} [built]
        + 9 hidden modules
    
    ERROR in ./node_modules/jquery.fancytree/dist/skin-lion/ui.fancytree.less
    Module build failed (from ./node_modules/less-loader/dist/cjs.js):
    Error: Cannot find module 'less'
    Require stack:
    - /home/kireto/axles/tmp/pesho2/node_modules/less-loader/dist/index.js
    - /home/kireto/axles/tmp/pesho2/node_modules/less-loader/dist/cjs.js
    - /home/kireto/axles/tmp/pesho2/node_modules/loader-runner/lib/loadLoader.js
    - /home/kireto/axles/tmp/pesho2/node_modules/loader-runner/lib/LoaderRunner.js
    - /home/kireto/axles/tmp/pesho2/node_modules/webpack/lib/NormalModule.js
    - /home/kireto/axles/tmp/pesho2/node_modules/webpack/lib/NormalModuleFactory.js
    - /home/kireto/axles/tmp/pesho2/node_modules/webpack/lib/Compiler.js
    - /home/kireto/axles/tmp/pesho2/node_modules/webpack/lib/webpack.js
    - /home/kireto/axles/tmp/pesho2/node_modules/webpack-cli/bin/utils/validate-options.js
    - /home/kireto/axles/tmp/pesho2/node_modules/webpack-cli/bin/utils/convert-argv.js
    - /home/kireto/axles/tmp/pesho2/node_modules/webpack-cli/bin/cli.js
    - /home/kireto/axles/tmp/pesho2/node_modules/webpack/bin/webpack.js
        at Function.Module._resolveFilename (internal/modules/cjs/loader.js:982:15)
        at Function.Module._load (internal/modules/cjs/loader.js:864:27)
        at Module.require (internal/modules/cjs/loader.js:1044:19)
        at require (/home/kireto/axles/tmp/pesho2/node_modules/v8-compile-cache/v8-compile-cache.js:161:20)
        at Object.<anonymous> (/home/kireto/axles/tmp/pesho2/node_modules/less-loader/dist/index.js:8:36)
        at Module._compile (/home/kireto/axles/tmp/pesho2/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
        at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
        at Module.load (internal/modules/cjs/loader.js:1002:32)
        at Function.Module._load (internal/modules/cjs/loader.js:901:14)
        at Module.require (internal/modules/cjs/loader.js:1044:19)
        at require (/home/kireto/axles/tmp/pesho2/node_modules/v8-compile-cache/v8-compile-cache.js:161:20)
        at Object.<anonymous> (/home/kireto/axles/tmp/pesho2/node_modules/less-loader/dist/cjs.js:3:18)
        at Module._compile (/home/kireto/axles/tmp/pesho2/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
        at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
        at Module.load (internal/modules/cjs/loader.js:1002:32)
        at Function.Module._load (internal/modules/cjs/loader.js:901:14)
        at Module.require (internal/modules/cjs/loader.js:1044:19)
        at require (/home/kireto/axles/tmp/pesho2/node_modules/v8-compile-cache/v8-compile-cache.js:161:20)
        at loadLoader (/home/kireto/axles/tmp/pesho2/node_modules/loader-runner/lib/loadLoader.js:18:17)
        at iteratePitchingLoaders (/home/kireto/axles/tmp/pesho2/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
        at iteratePitchingLoaders (/home/kireto/axles/tmp/pesho2/node_modules/loader-runner/lib/LoaderRunner.js:165:10)
        at /home/kireto/axles/tmp/pesho2/node_modules/loader-runner/lib/LoaderRunner.js:176:18
        at loadLoader (/home/kireto/axles/tmp/pesho2/node_modules/loader-runner/lib/loadLoader.js:47:3)
        at iteratePitchingLoaders (/home/kireto/axles/tmp/pesho2/node_modules/loader-runner/lib/LoaderRunner.js:169:2)
        at runLoaders (/home/kireto/axles/tmp/pesho2/node_modules/loader-runner/lib/LoaderRunner.js:365:2)
        at NormalModule.doBuild (/home/kireto/axles/tmp/pesho2/node_modules/webpack/lib/NormalModule.js:295:3)
        at NormalModule.build (/home/kireto/axles/tmp/pesho2/node_modules/webpack/lib/NormalModule.js:446:15)
        at Compilation.buildModule (/home/kireto/axles/tmp/pesho2/node_modules/webpack/lib/Compilation.js:739:10)
        at /home/kireto/axles/tmp/pesho2/node_modules/webpack/lib/Compilation.js:981:14
        at /home/kireto/axles/tmp/pesho2/node_modules/webpack/lib/NormalModuleFactory.js:409:6
     @ ./app/javascript/packs/application.js 20:0-59
    
    Completed 200 OK in 2801ms (Views: 2800.1ms | ActiveRecord: 0.1ms | Allocations: 5363)
    
     
c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
shift + esc
cancel