External Haml Variable - ruby

I created a layout with a variable inside.
layout.haml:
- title = "Example"
%title #{title}
It works perfect and gave me this:
<title>Example</title>
But, if I put this variable in a partial, it doesn't work
_vars.haml:
- title = "Example"
layout.haml:
=partial "vars"
%title #{title}
How can I define all the variables on an external document and make it work?
Thanks for the help

You are probably looking for content for:
layout.html.haml:
%title= yield(:title)
_my_partial.html.haml:
- content_for(:title) do
Example

Maybe you could put your shared code in helper?
# application_helper.rb
def title
#title ||= 'Example'
end
After that title helper could be used either in primary view or in partial. Notice that calculation of variable will be performed only once due to ||=.

Related

How to use Slim directly in ruby

I would like to create a basic ruby script that renders Slim templates into html (This would eventually be part of a larger project). Ideally I would like to use the HTML produced within the script.
I understand this is possible using TILT (as shown in the SLIM README) where it says the following:
Slim uses Tilt to compile the generated code. If you want to use the Slim template directly, you can use the Tilt interface.
Tilt.new['template.slim'].render(scope)
Slim::Template.new('template.slim', optional_option_hash).render(scope)
Slim::Template.new(optional_option_hash) { source }.render(scope)
The optional option hash can have to options which were documented in the section above. The scope is the object in which the template code is executed.
However, I'm still unable to successfully run this. Therefore, I was wondering if someone could help me by producing a working example.
EDIT (this has recently been edited further ):
I have played about with the code quite a bit but I keep on getting the following error:
undefined local variable or method `source' for main:Object (NameError)
This is what i'm running:
require 'slim'
# I'm not sure about the next two lines...
optional_option_hash = {}
scope = Object.new
Tilt.new('template.slim').render(scope)
Slim::Template.new('template.slim', optional_option_hash).render(scope)
Slim::Template.new(optional_option_hash) { source }.render(scope)
Many Thanks for all your help.
See Specifying a layout and a template in a standalone (not rails) ruby app, using slim or haml
This is what I ended up using:
require 'slim'
# Simple class to represent an environment
class Env
attr_accessor :name
end
scope = Env.new
scope.name = "test this layout"
layout =<<EOS
h1 Hello
.content
= yield
EOS
contents =<<EOS
= name
EOS
layout = Slim::Template.new { layout }
content = Slim::Template.new { contents }.render(scope)
puts layout.render{ content }
For the scope, you can put in modules/classes or even self.
Quick essentials of
module SlimRender
def slim(template, variables = {})
template = template.to_s
template += '.slim' unless template.end_with? '.slim'
template = File.read("#{ROOT}/app/views/#{template}", encoding: 'UTF-8')
Slim::Template.new { template }.render OpenStruct.new(variables)
end
end
Include SlimRender to your class and:
def render_something
slim 'streams/scoreboard', scores: '1-2'
end

Sinatra method to set layout

I want to write a method in sinatra to set the layout, something like
def admin_layout
set :layout, 'admin/layout'
end
I know I can do things like set :erb, layout: :'main/layout' or specify the layout for each action like
get 'admin/login' do
erb :'admin/login', layout: :'admin/layout'
end
but I'm wondering if there is a way to just abstract that into a method so I don't need to set the layout for each route. I am making an app with a main site and then an admin site, but the admin part is very lightweight, just logging in and being able to edit posts so I am not trying to get too crazy but my current file structure is like this:
db/
models/
public/
views/
admin/
main/
app.rb
config.ru
Define a layout argument:
def admin_layout
{:layout, 'admin/layout'}
end
Then you can use this method as a param like
get 'admin/login' do
## do ......
erb :'admin/login', admin_layout
end
Or if you want to judge which layout it will use, change the admin_layout function like:
def admin_layout
if request.path.start_with?('/admin')
{:layout, 'admin/layout'}
else
{:layout, 'layout'}
end
end
I know I can do things like: set :erb, layout: :'main/layout'
No you can't do that--or at least erb will ignore it because it's not an erb specific option. If you could do that, wouldn't that do what you are asking for here:
but I'm wondering if there is a way to just abstract that into a
method so I don't need to set the layout for each route.
The method already exists--template():
#Templates:
application_layout = <<END_OF_HAML
%html
%head
%title My App
%body
=yield
END_OF_HAML
template :layout do #Creates a template named :layout
application_layout
end
template :page1 do
'%div.greet Hello World!' #=> <div class="greet">Hello World!</div>
end
template :page2 do
'%div#first_name John' #=> <div id="first_name">John</div>
end
#Routes: -------------------
get '/page1' do
haml :page1 #If there is a template named :layout, then the :page1 template will be inserted into the :layout template automatically.
end
get '/page2' do
haml :page2 #If there is a template named :layout, then the :page1 template will be inserted into the :layout template automatically.
end
Then you can override the default layout, like this:
admin_layout = <<END_OF_HAML
%html
%head
%title Admin Only
%body
=yield
END_OF_HAML
template :special_layout do #Creates a template named :special_layout
admin_layout
end
get '/page3' do
haml :special_layout, :layout => false do #Don't use default layout, i.e the :layout template, instead use :special_layout template
haml :page3
end
end
See "Named Templates" here: http://www.sinatrarb.com/intro.html#Named%20Templates

How can I use views and layouts with Ruby and ERB (not Rails)?

How can I use views and layouts with Ruby and ERB (not Rails)?
Today i'm using this code to render my view:
def render(template_path, context = self)
template = File.read(template_path)
ERB.new(template).result(context.get_binding)
end
This works very well, but how can I implement the same function, but to render the template inside a layout? I want to call render_with_layout(template_path, context = self), and so that it will have a default layout.
Since you tagged it with Sinatra I assume that you us Sinatra.
By default you view is rendered in your default layout called layout.erb
get "/" do
erb :index
end
This renders your view index with the default layout.
If you need multiple layouts you can specify them.
get "/foo" do
erb :index, :layout => :nameofyourlayoutfile
end
* If you don't use Sinatra you may want to borrow the code from there.
If you use the Tilt gem (which I think is what Sinatra uses) you could do something like
template_layout = Tilt::ERBTemplate.new(layout)
template_layout.render {
Tilt::ERBTemplate.new(template).render(context.get_binding)
}
If you are using Sinatra so it has a good docimentation and one of the topics it's nested layouts (see Sinatra README)
Also good idea to use special default layout file (layout.haml or layout.erb in your view directory) This file will be always use to render others. This is example for layout.haml:
!!!5
%html
%head
##<LOADING CSS AND JS, TILE, DESC., KEYWORDS>
%body
=yield ## THE OTHER LAYOUTS WILL BE DISPALYED HERE
%footer
# FOOTER CONTENT
Thanks for all the answers!
I solved it finally by doing this, I hope someone else also can find this code useful:
def render_with_layout(template_path, context = self)
template = File.read(template_path)
render_layout do
ERB.new(template).result(context.get_binding)
end
end
def render_layout
layout = File.read('views/layouts/app.html.erb')
ERB.new(layout).result(binding)
end
And I call it like this:
def index
#books = Book.all
body = render_with_layout('views/books/index.html.erb')
[200, {}, [body]]
end
Then it will render my view, with the hardcoded (so far) layout..

Why isn't my custom homepage appearing after deleting public/index.html?

I am trying to get my customized home page to appear instead of the Welcome Aboard You're Riding Ruby on Rails default page. In my config/routes.rb file I have the line root :to => 'pages#home' to let it load the pages/home.html.erb file, and I removed public/index.html as instructed in the comments of the routes.rb file. All the other web pages which I used the syntax match "/page_name", :to => "pages#page_name" are working fine. What more do I need to do to update my home page?
EDIT:
Someone asked me to post my pages controller. Here it is:
class PagesController < ApplicationController
def home
#title = "Home"
end
def contact
#title = "Contact"
end
def about
#title = "About"
end
def help
#title = "Help"
end
end
The #title variable is referred to in my .html.erb files, but otherwise my controller is pretty much empty.
Have you tried restarting the server after deleting index.html? Did you clear your browser cache?
Do you have a PagesController?
rails generate controller pages home
The syntax I use (Rails 2.3) is:
map.root :controller => "welcome"
That goes to the :index method. If you want to go to :home, I presume you would add :action.

Call Sinatra erb from another class

I need to render a Sinatra erb template inside a class in my controller. I'm having issues calling this though. I've looked in the Sinatra rdocs and have come up with this:
Sinatra::Templates.erb :template_to_render
When I do this, I get the following error:
undefined method `erb' for Sinatra::Templates:Module
Is there a way to call this from another class?
To imitate rendering behavior of Sinatra controller in some other class (not controller) you can create module like this:
module ErbRender
include Sinatra::Templates
include Sinatra::Helpers
include Sinatra::ContentFor
def settings
#settings ||= begin
settings = Sinatra::Application.settings
settings.root = "#{ROOT}/app"
settings
end
end
def template_cache
#template_cache ||= Tilt::Cache.new
end
end
Here you may need to tune settings.root
Usage example:
class ArticleIndexingPostBody
include ErbRender
def get_body
erb :'amp/articles/show', layout: :'amp/layout'
end
end
This will properly render templates with layouts including content_for
why you don't require 'erb' and after use only erb
## You'll need to require erb in your app
require 'erb'
get '/' do
erb :index
end
You could have your class return the template name and render it in the main app.
Of course that's not exactly an answer (I don't have enough rep to add a comment with this account) and you're probably doing just that by now anyway...

Resources