HAML layout.haml and Sinatra not working with url parameters - ruby

My index.haml is working fine with, for example:
get '/about' do
haml :about
end
But if I try to use a user parameter like:
get ':user/add' do
haml :add_item
end
The layout.haml is ignored.
I was trying to get this to work using subdirectories in my view folder like:
/view/contact/add.haml
While it inserts the =yield content, it will not show the layout.haml css styles, etc.
So I thought using subdirectories was the issue and put all my hamls in the base views directory. However it seems that anything using a url parameter like get ':user/add' does not incude the layout.haml regardless. Currently this is a test I did:
myapp.rb
require "rubygems"
require "sinatra"
require "haml"
require "data_mapper"
require "pony"
get '/' do #works fine
haml :index
end
get '/:user_id/dashboard' do #recognizes the content but ignores layout.haml
haml :dashboard
end
my layout.haml looks like this:
views/layout.haml
!!!
%html
%head
%title Testing haml and sinatra
%link(rel="stylesheet" href="css/style.css")
%body
#wrapper
#header
%h1 HAML Test Template
%h2 Made with Sinatra and HAML!
#navigation
%h1 Navigation
#sidebar
%h1 Sidebar
#content
=yield
#footer
%p
This is the footer.
Any help would be much appreciated. Thanks.
I don't know if it matters but I'm using shotgun for development

I fixed this by using the following in layout.haml:
layout.haml
Instead of:
%link(rel="stylesheet" href="css/style.css")
Replaced (fixed version):
%link(rel="stylesheet" href="/css/style.css")
Works fine! Hopefully this helps someone.

If it helps, when I view source, it appears that it's trying to access my style.css in the wrong place based on the url parameter ":user_id" like so:
http://127.0.0.1:4567/test/myapp/css/style.css
So I need to get it to grab the style sheet form the same place it would if I was hitting 127.0.0.1/about which would look like this in the html source:
http://127.0.0.1:4567/css/style.css
In the actual code both stylesheet links are identical, but since I'm in a subdirectory it cannot find the stylesheet style.css
http://127.0.0.1:4567/css/style.css *(exists in public/css/style.css)*
-vs-
http://127.0.0.1:4567/test/myapp/css/style.css *(doesn't exist)*

I am still seeing an issue now with url parameters using a variable in the url path with sinatra and Haml.
When using these I am seeing the css becoming embedded into the post processed html instead of creating a link to the style.css file. The processed html is as follows (even the doctype is messed up and title isn't included):
I see this now with url parameters in the path (e.g. localhost:4567/user/add):
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body { text-align:center;font-family:helvetica,arial;font-size:22px;
color:#888;margin:20px}
#c {margin:0 auto;width:500px;text-align:left}
</style>
</head>
Instead of this (e.g. localhost:4567/about):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Test app</title>
<link href='/css/style.css' rel='stylesheet' />
</head>
What am I missing here??

Related

How to call js and css files inside a html.erb file

I'm quite new to Ruby and ERB and for this case I'm using only Ruby and not rails.
E:\ruby
-app.rb
-plan.html.erb
-check.css
-track.js [js + jquery framework]
Inside app.rb I've the following lines
text = File.open(("final.html"), "w+")
text.puts ERB.new(File.read("plan.html.erb")).result binding
I'm not sure how to call the .js and .css files inside the .html.erb file. Kindly let me know if I've to post the .html.erb file in case that would be helpful to debug further, thanks.
You can include the JavaScript in the .html.erb file in the same way you load the text file. The simplest (code wise) solution is doing something along the lines of this:
plan.html.erb
<script>
<%= File.read('some/file.js') %>
</script>
However if you are expecting a <script src="some/file.js"></script> as result you'll have to create your own helper or use an existing one from some light weight web framework. A simple example might be:
lib/html_helpers.rb
require 'builder'
module HtmlHelpers
def javascript_include_tag(path)
Builder::XmlMarkup.new.script('', src: path)
#=> %{<script src="#{html_escaped_path}"></script>}
end
end
plan.html.erb
<% require 'html_helpers' %>
<% include HtmlHelpers %>
<%= javascript_include_tag('some/file.js') %>
Keep in mind that the first solution doesn't escape any HTML characters. Meaning that if your script contains </script> everything following that tag will be interpreted as HTML.

Rails aways renders the application.html.erb instead of wanted views

My Ruby on Rails application always renders the layouts/application.html.erb view instead the views I want it to. Has anyone an Idea why that might be so?
My routes file looks like this:
Rails.application.routes.draw do
root 'startup#index'
resources :users
end
And my application_cotroller.rb is pretty much empty:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end
By default, a controller action in Rails renders the view template for your action, wrapped up into a layout (which is application/layout)
ActionView::TemplateHandlers manages the lookup for the extension (.html.erb, .html.haml, .json.erb, etc ...)
so, in an action called index, you will get this implicit call unless you call render yourself :
def edit
# your code
render action :'edit', layout: 'application/layout' # implicitly called
end
Rails will then start processing your layout and put the content of your edit template in place of any yield within your layout. Thus, a typical layout will look like this :
<!doctype html>
<head>
</head>
<body>
<!-- layout content before view -->
<%= yield %>
<!-- layout content after view -->
</body>

SCSS styles not being shown in the Sinatra app from "Jump Start Sinatra" book

I was following along to the tutorial in the book Jump Start Sinatra and I have looked over the file for typos. But for some reason the styles wont show up.
Here are the instructions
This is what I have
main.rb
require 'sass'
require 'sinatra'
require 'slim'
require 'sinatra/reloader' if development?
get('/styles.css'){ scss :styles }
get '/' do
slim :home
end
get '/about' do
#title = "All about this website"
slim :about
end
get '/contact' do
slim :contact
end
not_found do
slim :not_found
end
require 'sass'
get('/styles.css'){ scss :styles }
The book said to delete the old styles.css from the public folder, which I did (and that was previously working fine). And the book did say to included the styles.scss in the views directory. Here is my structure and styles.css file
Does this imply that I should also remove the reference to the CSS file that I had in the layout.slim file? This is what I have there now
layout.slim
doctype html
html lang="en"
head
title== #title || "Songs by Sinatra"
meta charset="utf-8"
body
header
h1 Songs by Sinatra
== slim :nav
section
== yield
What I am missing? is it a typo? am I forgetting to do something? does the book have a gap in information that it assumes that a reader would know to do? I added the code, then ran gem install sass and restarted the server. So what could i possibly be missing?
Ok so this had multiple errors. Hopefully my explanation can prompt you to improve your problem solving skills.
I did have some typographical errors in my styles.css file as pointed out in comments. So to test it I visited their repo on github. Then copy/pasted into my file.
Then I did notice that the author did a poor job in explaining what should be done in the layout file. So I checked his file in the repo (by the way,what is written in the book's previous chapter was not accurate). Anyways here is the layout file that worked
layout.slim
doctype html
html lang="en"
head
title== #title || "Songs by Sinatra"
meta charset="utf-8"
link rel="stylesheet" href="/styles.css"
body
header
h1 Songs by Sinatra
== slim :nav
section
== yield
What was needed was the modification to refence the CSS file
link rel="stylesheet" href="/styles.css"

Am I loading scripts correctly in sinatra?

I have never done anything in sinatra before and decided to try it out on a project. I am confused on how script loading works. It seems to be intermittently working. Sometimes 2 scripts/css files will have internal server errors, and sometime they will all have errors.
This is my layout.erb :
<!doctype html>
<html>
<head>
<title>An HTML5 box of sand</title>
<meta charset="utf-8" />
<link href='http://fonts.googleapis.com/css?family=Arvo' rel='stylesheet' type='text/css'>
<link rel="stylesheet/less" type="text/css" href="/assets/stylesheets/style.less">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script><!--loads jquery-->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script><!--loads jquery ui-->
<script type="text/javascript" src="/assets/js/lib/handlebars.js"></script>
<script src="/assets/js/lib/less-1.3.0.min.js" type="text/javascript"></script>
<script type="text/javascript" src="/assets/js/script.js"></script><!--This is the place where you play!!!-->
</head>
<body>
<%= yield %>
</body>
</html>
I have the assets folder inside of the public folder /public/assets. It is weird because sometimes it will load the assets/js/script.js file, and not load the handlebars file. Other times it will load the handlebars and not the script.js file. I am not sure what is going on.
~~~~~~~~~~~~~~~~~UPDATE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Discovered the problem but don't know how to fix it.
So, it seems that because I am using data mapper the auto_migrate! method is somehow screwing with how the assets are being loaded. Is there something I can do about this. Here is what I have in my app.rb file:
require 'rubygems'
require 'sinatra'
require 'data_mapper'
# Include the models
require './models/User'
# Connect to mysql
DataMapper.setup(:default, "mysql://root#localhost/dev_landing")
#This line is what is messing everything up.
DataMapper.auto_migrate!
set :public_folder, 'public'
get '/' do
erb :home
end
I set up data mapper like this because I read in a tutorial that this is how you get it to automatically create the tables you specify in your models. Is there a better way to do this so that it is not messing up the loading of my scritps and css?
DataMapper.auto_migrate! deletes existing tables in case they exist and creates them again.
So calling this function means: you lose all your data. (That's why there is an exclamation mark at the end, meaning: watch out!) In case your schema is still under heavy development, I suggest you to replace DataMapper.auto_migrate! by DataMapper.auto_upgrade!. It does not wipe your old data, instead it tries to modify the underlying tables while trying to keep the data. The exclamation mark is still there because your data might still get slightly damaged because changing the schema without corrupting the data is not always possible.
Another thing, the order of calls must be changed. Currently it is:
Model definitions
DataMapper.Setup
DataMapper.auto_migrate!
Your route definitions etc.
But it should be instead:
DataMapper.Setup
Model definitions
DataMapper.auto_migrate! DataMapper.auto_upgrade!
DataMapper.finalize (you forgot that one)
Your route definitions etc.
When something is screwed up with datamapper, the error messages can be weird/misleading. By the way, make sure that there are no calls to the database from inside your views. These calls belong into the controller, without any exception in my opinion. This way your app naturally follows the MVC pattern. (After all Sinatra hardly enforces any other structure... ;))

Nokogiri/Mechanize xpath locator breaks when there is a stray start tag

I loaded a page using Mechanize:
url = 'http://www.blah.com'
agent = Mechanize.new
page = agent.get(url)
and tried to access an element using an XPath selector:
found = page.at('/html/body/table')
It returns nil because the HTML, which is out of my control, has an opening tag where it shouldn't be:
<html>
<body>
<tr>
<table>
. . .
The "stray start tag," as Firefox calls it, is ignored when the browser renders the page in real life (and Firefox gives me xpaths that ignore it), but Nokogiri can't see anything past that extra <tr>.
Is there any way to clean the HTML of hanging tags like this?
In your example it would be:
page.at '/html/body/tr/table'
But maybe it makes more sense to just do:
page.at 'table'
Use a less brittle XPath query?
found = page.at('//table')
You can clean this using Nokogiri easily:
require 'nokogiri'
html = '<html><body><tr><table><tr><td>foo</td></tr></table></tr></body></html>'
doc = Nokogiri::HTML(html)
inner_table = doc.at('//body/tr/table')
if (inner_table)
doc.at('body tr').replace(inner_table)
end
puts doc.to_html
With the result being:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><table><tr><td>foo</td></tr></table></body></html>
If your HTML is more complex, then find some sort of marker similar to the <body><tr><table> node-chain, and substitute it into the code above.
Note that I'm mixing both XPath and CSS accessors. I prefer CSS for their readability, but sometimes XPath makes it easier to get at something or is more self-documenting.
Also notice that I'm using both XPath and CSS with Nokogiri's at method. Though Nokogiri supports both at, at_css and at_xpath, I rely on at unless I need to explicitly tell Nokogiri that what I'm using as an accessor is CSS or XPath. It's a convenience thing. The same applies to Nokogiri's search method.

Resources