Trouble getting a top level page to Ember


(Mittineague) #1

I’ve had fairly good experiences using plugin-outlets, but I wanted to improve my Discourse plugin dev chops.

So I decided I’d try to see if I could put together Ruby and Ember code by following this (that seems to be more about modifying Core files than plugins)

I have a plugin.rb

# name: discourse-newpage
# about: learning exercise
# version: 0.1
# authors: Mittineague
# url: https://github.com/Mittineague/no-repo-for-this.git

enabled_site_setting :mitt_newpage_enabled

module ::DiscourseNewpage
  def self.plugin_name
    'discourse-newpage'.freeze
  end
end

after_initialize do

  module ::DiscourseNewpage
    class Engine < ::Rails::Engine
      engine_name "discourse-newpage"
      isolate_namespace DiscourseNewpage
    end
  end

  DiscourseNewpage::Engine.routes.draw do
    get '/newpage' => 'newpages#index'
    get '/newpage/:id' => 'newpages#show'
  end

  Discourse::Application.routes.append do
    mount DiscourseNewpage::Engine, at: "/"
  end

  require_dependency 'application_controller'
  class DiscourseNewpage::NewpagesController < ::ApplicationController

    def index
      render json: { name: "donut", description: "delicious!" }
    rescue StandardError => e
      render_json_error e.message
#      render text: 'Just sayin'			# at newpage.json !?
#      render inline: "<%= 'hello , ' * 3 + 'again' %>"	# at newpage.json !?
    end

    def show
      render json: { name: "cake", description: "moist!" }
    rescue StandardError => e
      render_json_error e.message
#      render text: 'Just sayin'			# at newpage.json !?
#      render inline: "<%= 'hello , ' * 3 + 'again' %>"	# at newpage.json !?
    end
  end
end

By going to localhost:3000/newpage.json or localhost:3000/newpage/3.json I get the index and show (which oddly can also display “text” and “inline” by going to “json” when they are the “render”)

I have a newpage-route-map.js.es6 file that currently is like

export default {
  map(function(){
    this.route('newpage', { path: '/index' });
    this.route('newpage/:id', { path: '/show' });
  });
}

and I have templates/.hbs and routes/.js.es6 files for “index” and “show”

After spending quite a bit of time the past few days trying countless variations of uppercase, lowercase, camelcase, slashes, periods, hyphens, different resources, different paths, etc. etc. etc. I have gone well beyond making educated best guesses and gone into throwing against the wall to see if it sticks territory.

No matter what I have tried doing, without the “.json” I invariably get the “OOPS!” page.

Maybe I’m missing the obvious?
Maybe it is not possible at all?
Maybe I need to extend a different controller?

Any and all suggestions are most welcome. TIA


(Robin Ward) #2

I’d recommend reviewing the ember routing guide.

Your route map should probably look like this instead:

this.route('newpage', { path: '/newpage', resetNamespace: true }, function() {
  this.route('show', { path: '/:id' })
});

Then you can create templates as: templates/newpage-show.hbs and templates/newpage-index.hbs. Your routes would be routes/newpage-show.js.es6 and routes/newpage-index.js.es6.

Also, you should install the Ember Inspector which will show you the routes you’ve defined in your developer console.


(Mittineague) #3

If I muck up the “mount at” and go to a “.json”, in the Action Controller Exception page I can see the routes are added (as far as Ruby is concerned)

					Routes for DiscourseNewpage::Engine
newpage_path 	GET 	/newpage(.:format) 		discourse_newpage/newpages#index
				GET 	/newpage/:id(.:format) 	discourse_newpage/newpages#show 

But when I use Ember Inspector “Routes” I’m not seeing any added by the plugin.

LOL, I have more than once. Obviously whatever it is I need to know hasn’t “clicked” by my reading them, so I have installed Ember and am working my way through the tutorial.


(Mittineague) #4

I’ve worked a good way through the Ember tutorial, read the documentation several times over.

I’ve tried so many different tweaks that I think I could type

cd ~/discourse 
exec rails s

in my sleep and if I ever saw anything other than “Oops! That page doesn’t exist or is private.” I might go into shock.

I removed the “show/:id” code in hopes it would simplify things enough. but even so I have not yet been able to put anything into the application.hbs {{outlet}} by trying different resources, including app, application, discourse, home, index, root, and site, or the plugin-name or no resource at all…

In the mapping-router.js.es6 L21-L23 I see

// Ember’s router can’t be extended. We need to allow plugins to add routes to routes that were defined
// in the core app. This class has the same API as Ember’s Router.map but saves the results in a tree.
// The tree is applied after all plugins are defined.

so I’m thinking there must be a way, just that I’m not seeing it.

I’ve dug through the code for several plugins. Most have “add_admin_route”.
One that does not is the Cakeday plugin so I’ve spent more time looking at that one than others, But I have yet to make the non-json URL work

Dev Tools Network shows a 200, but I think it is really a soft 404

The thin CLI shows

I, [2017-01-25T01:33:53.969915 #2233] INFO – : Started GET “/newpage” for 127.0.0.1 at 2017-01-25 01:33:53 -0500
D, [2017-01-25T01:33:54.115992 #2233] DEBUG – : Permalink Exists (3.0ms) SELECT 1 AS one FROM “permalinks” WHERE “permalinks”.“url” = ‘newpage’ LIMIT 1 [[“url”, “newpage”]]
I, [2017-01-25T01:33:54.123765 #2233] INFO – : Processing by DiscourseNewpage::NewpagesController#index as HTML
I, [2017-01-25T01:33:54.161635 #2233] INFO – : Rendered default/empty.html.erb within layouts/application (0.2ms)
I, [2017-01-25T01:33:54.173263 #2233] INFO – : Rendered layouts/_head.html.erb (0.5ms)

The “as HTML” seems like a clue, but what exactly, I don’t know.

Current plugin.rb

# name: discourse-newpage
# about: learning exercise
# version: 0.1
# authors: Mittineague
# url: https://github.com/Mittineague/discourse-newpage.git

enabled_site_setting :mitt_newpage_enabled

after_initialize do

  module ::DiscourseNewpage
    class Engine < ::Rails::Engine
      engine_name 'discourse-newpage'
      isolate_namespace DiscourseNewpage
    end
  end

  ::DiscourseNewpage::Engine.routes.draw do
    get '/newpage' => 'newpages#index'
  end

  require_dependency 'application_controller'

  Discourse::Application.routes.append do
    mount ::DiscourseNewpage::Engine, at: "/"
  end

  module ::DiscourseNewpage
    class NewpagesController < ::ApplicationController

      def index
        render :json => { name: "succotash", description: "yellow and green" }
      rescue StandardError => e
        render_json_error e.message
#      render text: 'Just sayin'			# at newpage.json !?
#      render inline: "<%= 'hello , ' * 3 + 'again' %>"	# at newpage.json !?
      end

    end
  end

end

Current discourse-newpage-route-map.js.es6 (have also tried without the “discourse-”

export default function() {
  this.route('newpage', { path: '/newpages#index', resetNamespace: true });
}

(Alan Tan) #5

Do you have a repo for this plugin somewhere? If so push it up on GitHub and I’ll have a look


(Mittineague) #6

I hadn’t as I was only hacking away in my localhost Vagrant setup. But I do now.


(Joe Buhlig) #7

This has come up in a number of places so I decided to give it a go. I played around with it this morning. Try this:

Edit:
I have a little more time now to explain. :wink:

The main difference I made was to change the route map. I could see that the route map code (discourse-newpage-route-map.js.es6) was running but the route code itself (/routes/newpage/index.js.es6) wasn’t. Looking at some of my other plugins (not yet public) I realized I normally use this pattern for page routes: /routes/newpage-index.js.es6 But that still didn’t solve everything.

So I suspected the Ruby routing as an issue since I couldn’t get a byebug to show me that the controller was firing. So I effectively recreated the entire routing and engine set up to follow my normal pattern. Calling /newpage.json worked so I figured that end was correct. But something was off with directing the route through the engine so I assigned the route to Discourse itself instead.

I can’t say that anything in particular was the magic bullet but the combination of renaming pieces on the Ember side and reconfiguring the Ruby side made it all work out.


(Mittineague) #8

Thanks,

It is still giving me the JSON with “/newpage.json” and the Oops! with “/newpage”.

As this worked for you, maybe there is something different with my Settings?

I have Latest as “home”, do you have another?


(Joe Buhlig) #9

Do you get an error in the console at all? Or a error trace in the console? I sometimes drop a console.log("XXXXXXXXXXXXXXX"); into the routers to see what fires and when. That’s what helped me get this working on my end.

I can’t think of a reason these would affect this in any way.


(Mittineague) #10

Ah, after a week a light finally shines.

The closest thing I could see as an “error” was in the CLI.

Ember inspector never showed the route, and console never showed any errors or log messages.

So as far as I could tell the code was never getting to Ember.

Anyway …

I have 2 localhost Discourse installs. Both are
Windows 10 -> VMware -> Ubuntu 16.04 LTS

One I followed an earlier version (sans the DO stuff) of
discourse/INSTALL-cloud.md at master · discourse/discourse · GitHub

the other
Beginners Guide to Install Discourse on Ubuntu for Development

The first I have been using more as a non-techy Admin to test Discourse operations and occasionally a “beta” plugin.

The second for “hacks” i,e. modified Core code, and “pre-alpha” plugins.

A reason is I want to keep the first as “clean” of my muddy footprints as I can, but also workflow.

For example, the first is
tweak - push - rebuild app - test - repeat
the second is the easier and faster
tweak - exec rails s - test - repeat

Though you code does not work on my “hack” install, it does work on my “clean” install.

Other than the second involving Vagrant, a difference is the firsts root is “localhost” and the seconds is “localhost:3000” - with a port number

I did enter “3000” in Admin -> Developers and Discourse uses it for internal URLs but I’m guessing the presence of the port has very much to do with the road block I was hitting.


(Joe Buhlig) #11

:confetti_ball: :tada: Woohoo!


(Mittineague) #12

Gah! How could I have forgotten.

Instead of starting the server with only exec rails s I tried starting with
exec rails s -b 0.0.0.0

Then the code works with the “hacks” Vagrant install too.

I tried Cakeday and it worked both regardless, so there is something different about it I’d like to know about.


(Joe Buhlig) #13

I would imagine the Ruby side of the routing would cause issues with weird port numbers and such. That may be why the json worked but the page didn’t.


(Mittineague) #14

I don’t really know. IIRC, a few years ago I set up a Github -> VirtuaBox -> Vagrant install. It was slow but started up OK with bundle exec rails s
Then after some time, Discourse wouldn’t load up at all unless it was started with bundle exec rails s -b 0.0.0.0
Then after some time the whole set-up wouldn’t work so I scrapped that and did the current VMware.

I guess it could be something I did wrong, changes in Discourse code, changes in dependency Gems. changes in some VM code. Any one or a combination thereof.

When it comes to SysOp stuff I’m in over my head. Successful installs are often more a matter of luck than any great understanding of what I’m doing. And when I do know something it’s usually because I did it wrong a few times and learned the hard way.


(Mittineague) #15

Curiouser and curiouser.

It seems I spoke too soon. I removed the Cakeday plugin from my “hack” install and was preparing to experiment with the “newpage” plugin.

It no longer worked, even with the -b 0.0.0.0

I tested several times and it looks that it isn’t a thin vs. puma or with or without the -b 0.0.0.0, but whether or not Cakeday is installed (doesn’t need to be enabled, only installed. As long as Cakeday is installed “newpage” works on “hack” regardless of how a server is started.

Yet on “clean”, “newpage” works even without Cakeday being installed.

This IIFE looks like it might be involved, but I’m still not seeing how Cakeday affects things.

<script>

  (function() {
    var ps = require('preload-store').default;

    Discourse.CDN = '';
    Discourse.BaseUrl = 'localhost'.replace(/:[\d]*$/,"");
    Discourse.BaseUri = '';
    Discourse.Environment = 'development';
    Discourse.SiteSettings = ps.get('siteSettings');
    Discourse.LetterAvatarVersion = '5_ca57bbc3b601d8717c1d63514c51fac8';
    I18n.defaultLocale = 'en';
    Discourse.start();
    Discourse.set('assetVersion','d41d8cd98f00b204e9800998ecf8427e');
    Discourse.Session.currentProp("disableCustomCSS", false);
    Discourse.HighlightJSPath = "/highlight-js/localhost/133b1767dbeecf92cad6dfc38d42cde22195db05.js";
  })();
</script>

(Joe Buhlig) #16

What’s different about “hack” vs “clean”? I looked through Cakeday. It’s pretty straightforward with the only potential (that I saw) is it adds routes as well. But that shouldn’t affect anything as most plugins do this in some way.


(Mittineague) #17

For the “hacK” install I was able to cd ~/discourse and run rake about

Rails version             4.2.7.1
Ruby version              2.3.0-p0 (x86_64-linux)
RubyGems version          2.6.8
Rack version              1.6.5
JavaScript Runtime        mini_racer (V8)
Middleware                MessageBus::Rack::Middleware, 
  Rack::MiniProfiler, 
  Middleware::TurboDev, 
  Middleware::MissingAvatars, 
  Rack::Sendfile, 
  ActionDispatch::Static, 
  Rack::Runtime, 
  Rack::MethodOverride, 
  ActionDispatch::RequestId, 
  SilenceLogger, 
  Logster::Middleware::Reporter, 
  ActionDispatch::ShowExceptions, 
  Logster::Middleware::DebugExceptions, 
  BetterErrors::Middleware, 
  ActionDispatch::RemoteIp, 
  ActionDispatch::Reloader, 
  ActionDispatch::Callbacks, 
  ActiveRecord::Migration::CheckPending, 
  ActiveRecord::ConnectionAdapters::ConnectionManagement, 
  ActiveRecord::QueryCache, 
  ActionDispatch::Cookies, 
  ActionDispatch::Session::DiscourseCookieStore, 
  ActionDispatch::Flash, 
  ActionDispatch::ParamsParser, 
  Rack::Head, 
  Rack::ConditionalGet, 
  OmniAuth::Builder, 
  Rack::Protection::FrameOptions
Application root          /home/mittineague/discourse
Environment               development
Database adapter          postgresql
Database schema version   20161216101352

For the “clean” I was able to cd /var/discourse then ./launcher enter app then rake about

Rails version             4.2.7.1
Ruby version              2.3.3-p222 (x86_64-linux)
RubyGems version          2.5.2
Rack version              1.6.5
JavaScript Runtime        mini_racer (V8)
Middleware                Middleware::RequestTracker, 
  MessageBus::Rack::Middleware, 
  Rack::MiniProfiler, 
  Rack::Sendfile, 
  Rack::Runtime, 
  Rack::MethodOverride, 
  ActionDispatch::RequestId, 
  SilenceLogger, 
  Logster::Middleware::Reporter, 
  ActionDispatch::ShowExceptions, 
  Logster::Middleware::DebugExceptions, 
  ActionDispatch::RemoteIp, 
  ActionDispatch::Callbacks, 
  ActiveRecord::ConnectionAdapters::ConnectionManagement, 
  ActiveRecord::QueryCache, 
  ActionDispatch::Cookies, 
  ActionDispatch::Session::DiscourseCookieStore, 
  ActionDispatch::Flash, 
  ActionDispatch::ParamsParser, 
  Middleware::AnonymousCache, 
  Rack::Head, 
  Rack::ConditionalGet, 
  OmniAuth::Builder, 
  Rack::Protection::FrameOptions
Application root          /var/www/discourse
Environment               production
Database adapter          postgresql
Database schema version   20161216101352

EDIT
To make it easier to see differences in the Middleware, here’s my list. The first is what’s in “hack” (aka development) that isn’t in “clean” (aka production), the second what’s in “clean” that isn’t in “hack”

array(6) {
  [4]=>
  string(24) "ActionDispatch::Reloader"
  [9]=>
  string(22) "ActionDispatch::Static"
  [11]=>
  string(37) "ActiveRecord::Migration::CheckPending"
  [13]=>
  string(24) "BetterErrors::Middleware"
  [17]=>
  string(26) "Middleware::MissingAvatars"
  [18]=>
  string(20) "Middleware::TurboDev"
}
array(2) {
  [13]=>
  string(26) "Middleware::AnonymousCache"
  [14]=>
  string(26) "Middleware::RequestTracker"

(Mittineague) #18

Well, I’m flummoxed. Different days, different gremlins.

While testing yesterday and today, the plugin now consistently works OK both production and development installs, with or without the cakeday plugin being installed.

I don’t have much luck with Heisenbugs :slight_frown: