So I have a webserver I've built using sinatra, the meat of which goes like this:
set :variable,"value"
get '/' do
erb :index
end
And, of course, the template in views/index.erb which looks something like this:
<html>
<!-- etc -->
<ul>
<% my_array.each do |thing| %>
<%="Something: #{thing}, variable from sinatra: #{settings.variable}"%>
<% end %>
</ul>
</html>
If you try running code like this you'll notice that you can't access sinatra's settings variable from inside erb templates. Any ideas how I can achieve this while keeping its simplicity?
Thanks in advance!
I was using an old version of Sinatra - updated to version 1.0 and it works fine :)
Thanks everyone!
I had a similar issue and the resolution was to make sure all the set :x, "y" stuff happened in the class declaration (of my subclass of Sinatra::Base) outside of the initialize method.
Related
Let's say I have a Ruby files structure like this:
app.rb
/views/index.erb
/views/layout.erb
app.rb is the main app file that contains the routes. Let's say I have one route as this:
get "/" do
erb :index
end
In layout.erb I have my html head and closing </body> and </html> and etc. It is also where I have <head>..</head> and where I can put that scope for some JavaScript methods.
Let's say now that I have my Ruby logic in index.erb. I get a value somehow from my logic (index.erb) and I want to pass that value to my layout.erb. Is it possible? If so, how we do that?
I have checked the #variable_name to pass it as argument from the route definition:
get "/" do
#variable_name = ??? -> this do not works since I did not get the logic yet from index.erb, no?
erb :index
end
I also have tried to use simply <%= variable_name %> or #{variable_name} directly in the layout.erb but without any success.
I actually found out that I was able to transport my "code" to view the widgets I wanted to populated in the index.erb so by that I resolve my problem of accessing the value that was define from a variable declared in index.erb.
Problem solved and a better way to work with Ruby as this issue makes me read more about how to structure myself (Thx to Dave).
I have a problem similar to some I've found on stackoverflow, but not quite the same. I'd like to avoid the solution to the following question:
https://stackoverflow.com/a/10407782/996587
Basically, would like the following HTML output:
<div class='myclass' extraattr='UNESCAPED <>& CONTENT'>
Content...
</div>
The HAML I'm using looks like this:
.myclass{ "extraattr" => "UNESCAPED <>& CONTENT" }
Content...
I can't quite figure out how to get the content to output the way I want. Tried applying .html_safe to the end of the string, but got the following error:
undefined method `html_safe' for "UNESCAPED <>& CONTENT":String
Later realized that for this particular application I'm not using Rails, just ruby + HAML. (I inherited this project and I'm just starting to learn HAML, ruby, and Rails anyways)
And again, for those of you too lazy to click links and didn't read the solution I referred to, I'd prefer not to configure HAML to not escape attrs for the entire file, just for this one attribute.
Thanks!
UPDATE
I just found the :plain filter, and was able to get what I wanted using that. However, if there's a trick I don't know about so I don't have to write all the HTML, I'd appreciate it. My "fix":
:plain
<div class='myclass' extraattr='UNESCAPED <>& CONTENT'>
Content...
</div>
There isn’t (currently) any way to turn off escaping for an individual attribute in Haml outside of Rails, it’s all or nothing using the :escape_attrs option. Depending on what you want, it might be worth looking at the :once option.
When Haml is used in Rails, it replaces the html escaping methods with some that respect the html_safe value that ActiveSupport adds (see lib/haml/helpers/xss_mods.rb).
It is possible to use these methods outside of Rails if you want. You will need to add html_safe and html_safe? methods to the String class in order for this to work (be careful here, this example is only a “poor man’s” version of the full XSS protection that Rails provides, it won’t really protect you from much but it will allow selective escaping of attributes).
Add the following somewhere after requiring Haml (it might be best in its own file that gets required):
class String
def html_safe?
defined?(#html_safe) && #html_safe
end
def html_safe
#html_safe = true
self
end
end
require 'haml/helpers/xss_mods'
module Haml::Helpers
include Haml::Helpers::XssMods
end
Now you can use html_safe on your strings, and Haml won’t escape them:
.myclass{ "extraattr" => "UNESCAPED <>& CONTENT".html_safe,
"otherextraattr" => "ESCAPED <>& CONTENT"}
Content...
Output:
<div class='myclass' extraattr='UNESCAPED <>& CONTENT' otherextraattr='ESCAPED <>& CONTENT'>
Content...
</div>
Have you tried using a \ to escape the characters.
{ :myattr => '\<\>\&' }
I have a sinatra app that is mostly using erb for templates, but I am adding some mustache partials for blocks of html that need to be rendered on both the server and client side. I have a "views" directory where I'm keeping all my templates, including the mustache templates I'm adding. For example, the structure looks something like this:
views/
index.html.erb
_wingding.html.erb
_widget.html.mustache
Let's say I'm rendering index.html.erb using this endpoint:
get '/' do
erb :index
end
And inside that template, I want to render both of the above partials [UPDATE: it turns out this partial method is not built into sinatra, but is included via a gem (see my answer for details), but it still relies on the main sinatra rendering component, so the problem here still stands.]. So index.html.erb contains:
<%= partial :wingding %>
<%= partial :widget %>
The erb partial (wingding) renders fine, but the mustache partial (widget) does not. It causes the application to throw an exception:
Template engine not found: mustache
I have included the 'mustache' gem in the project. I tried 'require mustache/sinatra' and register Mustache::Sinatra. Both of these statements worked, but didn't solve the problem above. Any idea how to tell sinatra about mustache so that it can render mustache partials?
I'm setting my views directory by including this configuration:
configure do
set :views, File.join(File.dirname(__FILE__), 'views')
end
Version numbers:
sinatra 1.3.1
mustache 0.99.4
ruby 1.9.3
So it turns out the gem listed in the solution in my other answer caches output, meaning you can't use it to include the same partial with different locals in the same request, which makes it worthless for my purposes. So here's another (admittedly hackish) solution that I've settled on. I created a helper that will just deliver the contents of a given view:
helpers do
def template_contents(path)
File.open("#{settings.views}/#{path}") { |f| f.read }
end
end
Then, I just do a regular Mustache#render:
<%= Mustache.render(template_contents('_widget.html.mustache'), { ... }) %>
This works great for my use case.
I figured this out. First, I must note something I didn't realize when I posted the question. partial is not actually built into sinatra. It is being included in my app as part of the sinatra-more gem (discontinued, most of it's functionality is now in a project called padrino, but still using sinatra-more in this app). The partial method is included like this:
require 'sinatra_more/render_plugin'
module Sinatra
register SinatraMore::RenderPlugin
end
Anyway, that just adds the partial method (along with some other rendering helpers) but this method falls back on the built-in sinatra rendering code, so this fact is independent of the actual issue at hand in this question -- that sinatra does not by default recognize the mustache template engine. Turns out someone created a super simple gem to make it work, sinatra-mustache. You simply include the gem and require the library:
require 'sinatra/mustache'
That's it -- it just works! No additional configuration necessary. If you're curious how it works, the source code is pretty simple. It's by no means a one-liner to register a new template engine with sinatra (even saying "register" is a misnomer -- you basically have to implement it), but it's still fairly simple.
UPDATE: This gem caches the output for a given request/template, so you can't use it a second time with different locals. I could see cases where that's okay, but that makes it worthless for my use case.
I have a page which renders several partials; on my local mac everything is fine but after I push to heroku and visit the page the order of the partials is different!
I render partials with the code below and thought I controlled the order with a file naming convention.
html.erb:
<% Dir["app/views/partials/ws/*.html.erb"].each do |ws| %>
<%= render 'partials/ws/' + File.basename(ws,'.html.erb').slice(1..-1) %>
<% end %>
The partials use a naming convention:
_ws_01-why.html.erb
_ws_02-what.html.erb
_ws_03-who.html.erb
_ws_04-where.html.erb
_ws_05-when1.html.erb
_ws_06-how.html.erb
Heroku renders in this order:
_ws_01-why.html.erb
_ws_02-what.html.erb
_ws_06-how.html.erb
_ws_04-where.html.erb
_ws_05-when1.html.erb
_ws_03-who.html.erb
I'm not sure how heroku is interpreting the naming convention / ruby loop order... Wondering if there is a better naming convection or logic to add in my loop to control the order?
Thanks!
Change this:
<% Dir["app/views/partials/ws/*.html.erb"].each do |ws| %>
to this:
<% Dir["app/views/partials/ws/*.html.erb"].sort.each do |ws| %>
You cannot be sure than an enumerator will choose the same order in all cases unless you force it somehow.
I'm new to Rails and I'm trying to learn it using Rails 3 (RC).
I have managed to use http://plist.rubyforge.org/ for supporting the output of plists. I would like to check with you guys to see if my approach is the right way to do it. Here goes:
In the gemfile I added gem 'plist'
In config/initializers/mime_types.rb I added Mime::Type.register "application/plist", :plist
In the controller, I added format.plist { render :plist => #product } in show
In the model, I added
def to_plist
attributes.to_plist
end
And finally, in the view file show.plist.erb, I have <%= raw #product.to_plist %>
Accessing for instance /products/2.plist works fine, but being new to Rails, I'm wondering if there are anything I should have done differently.
Looks right to me.
The only suggestion I have is to perhaps mix in the to_plist method into ActiveRecord::Base so that you don't have to define it over and over in each model. Perhaps this method will even support render_with syntax?
I'm about to do something similar myself.