0

I'm new to the ruby world, and Sinatra for that matter, so I have no choice but to ask here about the error I keep getting.

I'm using a combination of Rack + Sinatra with Slim as template engine. I have my app.rb setup as this:

module Pulsr

class StylusHandler < Sinatra::Base
  set :views, File.dirname(__FILE__) + '/stylus'

  get '/css/styles.css' do
    stylus :styles
  end
end

class Application < Sinatra::Base

  register Sinatra::ConfigFile

  config_file './config/config.yml'

  use Pulsr::Api
  use Pulsr::Routes

  enable :logging, :dump_errors if Sinatra::Base.development?
  disable :method_override, :run

  set :public_folder, File.join(:root.to_s, 'static')
  set :views, File.join(:root.to_s, 'views')
  #set :static_cache_control, [:public, max_age: 60 * 60 * 24 * 365] if Sinatra::Base.production?

end

end

And the Pulsr::Api and Pulsr::Routes are in two different files in a subdirectory. The issue I have is that slim tries to render the template relative to the path of the routes file, which looks like this:

module Pulsr
class Routes < Sinatra::Base
  get '/*' do
    slim :index
  end
end

end

So, my folder structure looks something like this:

- config
  - config.yml
  ...
- controllers
  - routes.rb
- views
  - index.slim
- app.rb
- config.ru
- Gemfile
...

I get this error: No such file or directory @ rb_sysopen - /Users/rolandjitsu/Projects/Products/pulsr/controllers/views/index.slim where the template is actually placed with one level up in the views folder.

Before I had all the code in the app.rb file, and , normally, it worked, but now I am unsure how to fix this path issue.

Roland
  • 9,321
  • 17
  • 79
  • 135

1 Answers1

2

You have set up your Routes class as a separate Sinatra application from your main app, and this means it has its own settings that are not shared. The views folder for the Routes app is therefore the default for that app, which is the the views directory inside the controllers directory.

The simple way to fix it would be to specify the views directory in the Routes class.

module Pulsr
  class Routes < Sinatra::Base

    # add this line
    set :views, File.expand_path(File.join(__FILE__, '../../views'))

    get '/*' do
      slim :index
    end
end

You could also set the app_file to be the main app file, the views, root and public_folder settings will all then be set based on that.

It looks like you don’t actually intend to create several separate applications, but rather split up your single app into several files. A possibly better way to do that would be to use extensions. You can create a module containing routes that you can include in your main application, and they will use the same settings as the main app.

module Routes # N.B modle not class

  # in this method you can add routes to the main app
  def self.registered(app)

    # you need to use 'app.get', not plain 'get'
    app.get '/*' do
      slim :index
    end
  end
end

Then in your main app call register Routes instead of use Routes. This is slightly more work to set up, but gives you more flexibility.

matt
  • 78,533
  • 8
  • 163
  • 197
  • I figured it must be something with the settings, because I tried something like `set :views, File.expand_path(File.join(__FILE__, '../../views'))` in my `routes.rb` file and it seemed like I got a new error, but the error about not being able to resolve the path was gone. I think I like the second way you posted better. The reason I'm splitting up the file is because I'm trying to achieve an architecture similar to MVC. True, I'm not making several separate applications, it's just one, and all routes will resolve to the index, because I'll use angular for navigating pages. – Roland Feb 16 '14 at 16:34
  • @rolandjitsu Something I didn’t mention in my answer: in your question you have `set :views, File.join(:root.to_s, 'views')`, which is wrong – it will produce `root/views`. You probably meant to use the app root setting. The default is `views` anyway, so you shouldn’t need that line at all. – matt Feb 16 '14 at 17:09
  • Yes, I thought that the `:root` will give me the root of my app path. Is there another way of getting that and append the needed string ? Indeed, I do not need it for my views, but I do need it for my static assets since they will be in another folder than the default `public` one – Roland Feb 16 '14 at 17:31
  • @rolandjitsu just use `root` (i.e. no `:`). Settings are available as methods in the class scope, inside a route you would need to use `settings.root`. – matt Feb 16 '14 at 17:35
  • 1
    @rolandjitsu another option would be to just reopen the main app class from different files and add routes etc. to it. Have a look at this other question for an example: http://stackoverflow.com/questions/5015471/using-sinatra-for-larger-projects-via-multiple-files – matt Feb 16 '14 at 18:00
  • Thanks @matt, it's really helpful for me since I'm just getting started with ruby :) – Roland Feb 16 '14 at 18:04
  • Besides the `self.registered` what other methods can I call or the module has , @matt ? I suppose the is something that gets called when I use the `register Routes`. – Roland Feb 16 '14 at 20:11