rubyonjets / jets

Ruby on Jets
http://rubyonjets.com
MIT License
2.6k stars 181 forks source link

Slim Template Support: ActionView required differently than in Rails? #251

Closed undefinedvalue closed 5 years ago

undefinedvalue commented 5 years ago

[edited: forgot to upgrade jets. Problem still exists in 1.8.14]

Checklist

My Environment

Software Version
Operating System OSX 10.14.4
Jets 1.8.14
Ruby 2.5.3

Expected Behaviour

Adding a new rails-compatible template engine should work the same way as in Rails.

For example, to add the Slim template engine, you just add it to your gemfile:

gem "slim"

In the case of Slim, it is written such that it detects if it is running in a Rails environment by seeing if ActionView is defined. If so, it does some special setup so it just works. Here is the code that does that: https://github.com/slim-template/slim/blob/master/lib/slim/template.rb

Current Behavior

Adding the Slim dependency in the Gemfile does nothing. This is because bundler requires it during Jets boot stage, but that happens before action_view is required, because action_view is lazily loaded. This means that at the time slim is required, ActionView is not defined, so the special Rails setup logic isn't executed.

In order to make it work, you need to change the Gemfile to not auto-require slim:

gem "slim", require: false

Then, in config/application.rb, require action_view before slim:

require "action_view"
require "slim"

Jets.application.configure do
...

With those changes, it works.

Step-by-step reproduction instructions

Add a dependency on slim:

gem "slim"

Generate a controller:

jets generate controller Pages index

Rename the new view from being erb to slim:

mv app/views/pages/index.html.erb app/view/pages/index.html/slim

For simplicity, make the new controller the root handler, so config/routes.rb is just:

Jets.application.routes.draw do
  root 'pages#index'
end

Run jets server and go to localhost:8888

You will get "Missing template pages/index ...", because it does not have the slim handler registered.

Code Sample

See repro steps.

Solution Suggestion

Not really sure how to fix this, but it might be related to the fact that actionview is a submodule dependency instead of a gem dependency of Jets. In Rails it is a gem dependency. So I think that Jets is basically bypassing the Bundler dependency ordering logic, but I'm not super familiar with that so don't take my word for it.

tongueroo commented 5 years ago

Yes. Jets uses a few components from Rails. Most of them are included as gems in a standard fashion, see jets.gemspec

However, the actionview component is currently a fork. FWIW, I'm not a fan of the fork and got some ideas on ways to remove it. Don't think the fork is the issue here though.

The reasons behind the fork originated here in this Jets Community Post Why does Jets define Rails module? The fork removes the Rails constant. This is because gems generally check for the Rails constant to detect if they are within a Rails application. But they are actually in a Jets application instead and the gem's setup logic does not work. The approach actually gives gems a chance to work with Jets.

Ultimately, It looks like you would like to use slim for template rendering. This reminds me of another person's request to use haml for rendering in this Jets Community Post Can I use haml template engine instead of erb? The details on how it was resolved is in that thread.

Similarly, to use slim, you can take some similar approaches:

  1. Add an initializer and that perform the setup logic there.
  2. Fork the slim gem and add support and use that version until it gets hopefully gets merged to the upstream project.
  3. Create an additional gem like slim-jets or something that adds support. You won't have to wait for the fork to be merged to the upstream in this case.

Think #1 might be the quickest option, which you’ve already kinda done in application.rb

Think #2 would be nice but it does require another thing for the slim project maintainers to support, which may, understandably, not be worth it.

Think #3 would be cool for someone who wants to get into open source and has some time to support it.

With options 2 and 3, think a Jet Turbine would need to be built. Turbines are how you extend Jets for stuff like this. Docs Jets Turbine. You could use the on_load hook

ActiveSupport.on_load(:action_view)

Designed the Turbine interface to closely resemble a Railtie so adding Jets support for gems is not too much work. Albeit there will be some work.

tongueroo commented 5 years ago

Hack together https://github.com/tongueroo/slim-jets Just add slim-jets to the Gemfile now.

gem "slim-jets"

Note, also removed the forked of ActionView in v1.9.8+