nesquena / rabl

General ruby templating with json, bson, xml, plist and msgpack support
http://blog.codepath.com/2011/06/27/building-a-platform-api-on-rails/
MIT License
3.65k stars 335 forks source link

Templates not found in view path #339

Open mattiassvedhem opened 12 years ago

mattiassvedhem commented 12 years ago

So I have my template in a namespaced Engine app/views/scheduler/schedules/show

Rabl::Renderer.new(
  'schedules/show',
  @schedules,
  view_path: 'app/views/scheduler',
  format: :json
).render
Rabl::Renderer.json(
  @schedules,
  'schedules/show',
  view_path: 'app/views/scheduler'
)

Both raises this error

Cannot find rabl template 'schedules/show' within registered (["app/views/scheduler"]) view paths!

However it does work in my specs within the Engine but not when using the Engine from the parent app.

rails (3.2.8) rabl (0.7.2)

databyte commented 12 years ago

I'm sure if it was just app/views/schedules/show, it'd work. I haven't set up anything in multiple nested views, so maybe someone else has tried.

Try throwing a debugger into RABL and trace the code a little to see where its looking that up. If you can't, then setup a dummy Rails app with the exact same scenario and send me a link to it - I can look at it then.

My preferences with questions or bugs is to recreate the issue via a broken spec in RABL or in a fixture/test app. It usually takes me longer to setup the bug than to find a solution and sometimes I just don't have time. Sorry.

mattiassvedhem commented 12 years ago

Hi @databyte thanks for taking the time.

As Engines are especially mentioned under view_path in the Readme I took for granted that it was supported =).

I've tried to figure out why it doesn't find the template, however without success.

I've set up a example application with a mounted isolated Engine (the Engine is placed in /lib). If you run the server and go to / you should see the error being raised.

https://github.com/mattiassvedhem/rabl-rendering

I fully understand that! I'll see if I can write a broken spec for it.

databyte commented 12 years ago

Thanks @yeggeps - everything is supported in open source - just as long as you don't mind coding it! (j/k, a little)

You don't have to have a broken spec if you have that sample app - that's plenty for me to work with. I'll look at it around my lunch break unless someone beats me to it.

mattiassvedhem commented 12 years ago

Hehe, fair enough. I'll rephrase it: I thought it was already supported, as the Readme briefly mentions it. ;)

Thanks a lot, I'll see if I come up with something.

mattiassvedhem commented 12 years ago

Ok, so observations so far:

nesquena commented 12 years ago

Interesting, thanks for raising this issue. Obviously it would make sense for RABL to support engines, and I think at some point on some version of Rails, I remember it was confirmed working. But things change all the time, thanks for investigating.

kmalakoff commented 11 years ago

I'm having a similar problem with a new Rails 3 project where we are evaluating JSON renderers using embedded engines (inside namespaces).

I've tried:

  config.view_paths << Rails.root.join('engines/my_engine/app/views/my_engine')

Using a .rabl file inside a view for a collection ('engines/my_engine/app/views/my_engine/my_models/index.rabl'):

collection @my_models
extends "my_models/show"

and in the model ('engines/my_engine/app/views/my_engine/my_models/show.rabl'):

object @my_model
attributes :id, :name

And it looks like it is ignoring the rabl_init.rb view_paths setting (I've tested that the file is being used by trying with and without include_json_root) but successfullyautomatically including the path to the non-namespaced engine view folder.

Missing partial my_models/show with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder, :coffee, :rabl]}. Searched in:
  * "/Users/kevin/Dev/RABLEvalBug/app/views"
  * "/Users/kevin/Dev/RABLEvalBug/engines/my_engine/app/views"

Any chance you could look into why the path isn't being picked up for the namespace? I've already spent 4 hours or so, but my Rails experience is low so I haven't been able to crack it on my own...I'd really appreciate it as I've looked at other solutions, but really prefer the RABL DSL and the awesome flexibility it brings.

I've created a shiny new project with the problem: https://github.com/kmalakoff/RABLEvalBug

To see the bug:

Cheers! (and a big please!)

kmalakoff commented 11 years ago

In the demo code that I submitted earlier, I was able to manually set the view_paths in my engine's application controller rather than using rabl_init.rb:

module MyEngine
  class ApplicationController < ActionController::Base
    # WORKAROUND: RABL's rabl_init.rb for view_paths doesn't configure correctly
    self.view_paths << Rails.root.join('engines/my_engine/app/views/my_engine')
  end
end

so I think a patch should be really straightforward! Unfortunately, I'm not sure how to debug 3rd party Gem code in an application and I've run out of time to devote to this.

If you can patch RABL directly for engine support, I'd be mighty happy.

nesquena commented 11 years ago

Yeah I will try to take a look when I get a chance, I definitely want to fix this, unfortunately I also don't know much about Rails Engines myself. @databyte any thoughts?

cnstaging commented 11 years ago

Another 'interesting' aspect to this issue is that if you include the following within the top level rails project Gemfile, it also fixes the issue. (*Not that good of a workaround for a distributed gem)

gem 'rabl' 

This leads me to believe that either a race condition or additional initialization can be added to the Rabl engine to ensure that it is loaded before the controller action is called.

nesquena commented 11 years ago

@cnstaging Can you try running Rabl.register! in an initializer and see if that fixes it? and remove it from the top level Gemfile?

cnstaging commented 11 years ago

Just putting ::Rabl.register! in the engine.rb and within an initializer did not work, but does highlight that Rabl is not loaded before other engines are.

Error NameError: uninitialized constant Rabl

So of course, the next step was simply to put a require 'rabl' at the top of the engine.rb.

That works. Rabl even works without the register command at this point.

I also tried it on another Rails engine within my project which did not have the "Rabl.register!" as an initializer and that rabl api also worked (after the other engine had the require 'rabl', simply as long as one of the engines required the 'rabl' gem it seems to work.

nesquena commented 11 years ago

Interesting, that's useful to know thanks! I think it has to do with RABL somehow not being loaded from the engine. Any idea on what I could change to make this easier? I honestly know next to nothing about Rails engines.

cnstaging commented 11 years ago

I played around with the differences between bundler loading the 'rabl' gem and bundler loading 'rabl' from a gemspec.

In summary, bundler auto requires a gem by default, yet not when it comes from a nested gemspec. As far as I can tell, nothing can be done within the 'rabl' codebase because it's basically on the load_path, and I do not know of any hooks. With more information I would also say that my issue is different from the OP.

A minor 'rabl' documentation could be added to highlight the use within Rails engines and nested gemspecs. A require 'rabl' is sort of the only workaround that will work across both bundled gems and nested gemspecs from within an Rails engine.

Reference: The following 'issue' sounds pretty close to what behavior I ran into. https://github.com/carlhuda/bundler/issues/1041#issuecomment-7542550

nesquena commented 11 years ago

I added to the wiki https://github.com/nesquena/rabl/wiki/Setup-rabl-with-rails-engines can you take a look and add anything there I may have missed. Thanks, appreciate you taking a look.

cnstaging commented 11 years ago

That looks great, I will keep that page in mind as we continue to use 'rabl' throughout our series of Rails engines.

We have idenfitied some concerns, but has not been an issue yet, such as how to have two Rails engines that both use Rabl, and have two Rabl configurations. If we run into these, we will post and issue for discussion. Thank you again!

You can also update the main readme to include the require 'rabl' to be consistent as well. https://github.com/nesquena/rabl#configuration

nesquena commented 11 years ago

OK, thanks please do. I updated the README with that require line as well as adding links to the new guides at the bottom.

nesquena commented 11 years ago

Also not sure what you guys are working on but I just decided to add a People Using RABL page so if you feel like it, perhaps add yourself to the list. Thanks.

kmalakoff commented 11 years ago

Thanks for looking into this. Putting require 'rabl' din't change anything for me. Stil not working.

I think the instructions could be clearer. I added the line to my initializer file, but it doesn't say what to add in terms of view_paths to allow the template to be found inside the engine namespaced hierarchy.

I tried this:

config.view_paths << Rails.root.join('engines/my_engine/app/views/my_engine')

and other combinations, but none worked. Maybe I'm missing something?

reggieb commented 11 years ago

@kmalakoff, when I've wanted to point to paths within an engine, one approach is to create a method in the engine, that returns the path relative to the engine.

So in my_engine/lib/my_engine.rb I'd create a method like this:

module MyEngine

  def self.path_to_views
    File.expand_path("../app/views/my_engine", File.dirname(__FILE__))
  end

  ......
end

Then in the host app I can add:

config.view_paths << MyEngine.path_to_views

For example, look at active_admin_load_path here:

https://github.com/reggieb/qwester/blob/master/lib/qwester.rb

yurifrl commented 10 years ago

I just got the same problem, think that might be rabl since the path it seems to be right

flyfy1 commented 8 years ago

Facing same issue here (after 2 yrs from the last post of this issue). Issue Cause: I'm using spree.. and I want to reuse the rabl template in my main repo (which is referencing to Spree)

alexisraca commented 7 years ago

Debuging this worked for me in the controllers

render inline: Rabl::Renderer.xml(@login, "app/views/scoped_directory/logins/show", view_path: Rails.root.to_s)