Ruby newbie here. I'm following the Rails Tutorial and got stuck around 5.3 re: routes.
I have 5 pages(home, about, help, contact), all with similar test set, and rspec is only failing for the tests on 'home'. Since I'm using application_helper, I shouldn't need to specify in home.html.erb, right? I also took the advise of understanding rails routes: match vs root in routes.rb and added "match '/static_pages/home' => 'static_pages#home'" to routes.db.
Been stuck on these 2 errors for a while. Please help. Thanks!
Errors:
1) Static pages Home page should have the h1 'Sample App'
Failure/Error: page.should have_selector('h1', text: 'Sample App')
expected css "h1" with text "Sample App" to return something
# ./spec/requests/static_pages_spec.rb:9:in `block (3 levels) in <top (required)>'
2) Static pages Home page should have the base title
Failure/Error: page.should have_selector('title',
expected css "title" with text "Ruby on Rails Tutorial Sample App" to return something
# ./spec/requests/static_pages_spec.rb:13:in `block (3 levels) in <top (required)>'
home.html.erb
<div class="center hero-unit">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
Ruby on Rails Tutorial
sample application.
</h2>
<%= link_to "Sign up now!", '#', class: "btn btn-large btn-primary" %>
</div>
<%= link_to image_tag("rails.png", alt: "Rails"), 'http://rubyonrails.org/' %>
static_pages_spec.rb
require 'spec_helper'
describe "Static pages" do
describe "Home page" do
it "should have the h1 'Sample App'" do
visit root_path
page.should have_selector('h1', text: 'Sample App')
end
it "should have the base title" do
visit root_path
page.should have_selector('title', text: "Ruby on Rails Tutorial Sample App")
end
it "should not have a custom page title" do
visit root_path
page.should_not have_selector('title', text: '| Home')
end
end
application.html.erb
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", media: "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
<%= render 'layouts/footer' %>
</div>
</body>
</html>
application_helper.rb
module ApplicationHelper
# Returns the full title on a per-page basis.
def full_title (page_title)
base_title = "Ruby on Rails Tutorial Sample App"
if page_title.empty?
base_title
else
"#{base_title} | #{page_title}"
end
end
end
routes.rb
SampleApp::Application.routes.draw do
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
match '/static_pages/home' => 'static_pages#home'
root to: 'static_pages#home'
end
Let me know if you need anything else. Thanks!
Have you removed the public/index.html file and visually verified that you can get to / in your browser, and that the expected template is being rendered? Your spec looks OK otherwise.
Related
It looks like for whatever reason sinatra will not recognize the "code" I use is my get "/library" do I tried putting it into a string but to no avail. taking out the quotation marks makes them an uninitialized method. Help is greatly appreciated!
require 'sinatra'
require 'sinatra/reloader'
require 'data_mapper'
enable :sessions
DataMapper.setup(:default, "sqlite://#{Dir.pwd}/project3.db")
class Code
include DataMapper::Resource
property :id, Serial
property :language, String
property :purpose, String
property :code_snippet, Text
end
DataMapper.auto_upgrade!
get "/snippet" do
erb :snippet, layout: :project3_template
end
post "/snippet" do
Code.create params
redirect to ("/library")
end
get "/library" do
#html = Code.all(language: HTML)
#css = Code.all(language: CSS)
#javascript = Code.all(language: Javascript)
#ruby = Code.all(language: Ruby)
erb :library, layout: :project3_template
end
get "/library/:id" do
#code = Code.get :id
erb :code_id, layout: :project3_template
end
my erb page
<h1>Code Library</h1>
<h2>HTML</h2>
<%= #html.each do |code| %>
<%= code.purpose %>
<hr>
<%= end %>
<h2>CSS</h2>
<%= #css.each do |code| %>
<%= code.purpose %>
<hr>
<%= end %>
<h2>Javascript</h2>
<%= #javascript.each do |code| %>
<%= code.purpose %>
<hr>
<%= end %>
<h2>Ruby</h2>
<%= #ruby.each do |code| %>
<%= code.purpose %>
<hr>
<%= end %>
Try to pass the view like this
erb :project3_template
where project3_template would be project3_template.erb in your views folder
Your # class variables should be visible in the view, regular variables you can pass like below, :name in this sample is what if passed by the client through a GET or POST, these are all present in the params array. You could also pass the whole params array.
erb :project3_template, :locals => {:name => params[:name]}
See https://github.com/sinatra/sinatra#accessing-variables-in-templates
Your view has one serious issue: the use of <%%> and <%=variable%>
<%%> is for embedding Ruby code that has to be executed
<%=variable%> is for embedding the contents of a variable.
In your case you need do do the following
<%#html.each do |code|%>
<%= code.purpose %>
<hr>
<%end%>
In my project, I have a few files:
1. main.rb
require 'sinatra'
set :public_folder, 'public'
set :views, 'views'
set :erb, :layout => :base
get '/' do
erb :layout
end
get '/about' do
erb :about
end
get '/contact' do
erb :contact
end
2. layout.erb
<% title="Songs By Sinatra" %>
<!doctype html>
<html lang="en">
<head>
<title>
<%=title %>
</title>
<meta charset="utf-8">
</head>
<body>
<header>
<h1><%= title %></h1>
<nav>
<ul>
<li>Home
</li>
<li>About
</li>
<li>Contact
</li>
</ul>
</nav>
</header>
<section>
<%=yield %>
</section>
</body>
</html>
<p>Welcome to this website that's all about the songs of the great Frank Sinatra.</p>
<img src="/images/sinatra.jpg" alt="Frank Sinatra">
3. about.erb
<p>
This site is a demonstration of how to build a website using Sinatra.
</p>
When I go to http://localhost:4567/about everything is OK, page loads, but when I go to http://localhost:4567/, I get an error: no block given (yield).
Can anyone explain what is the problem, and possible solution.
Thank you very much in advance.
You need to pass a block in
erb :layout
For <%=yield %> in layout.erb to work, you need to pass a block whose output will be placed at the location of `yield. In its simplest form, you can do something like this:
erb :layout { "This is what I want in output" }
Typically, you render another template:
erb :layout do
erb :about
end
More details in documentation.
TLDR; what #wandmaker says - you need to pass a block to :layout.
Understanding yield is essential for understanding Ruby. Basically, yield passes control from one scope to another. All methods in Ruby accept blocks but they ignore them unless they explicitly yield or call them:
"A RUBY STRING".downcase { p "I'm in a block!" }
# => "a ruby string"
But if the method calls yield, control is passed to the block and then passed back to the calling scope:
def yield_me
yield
end
yield_me { p "I'm in a block!" }
# => "I'm in a block!"
Alternatively, you can catch blocks as arguments:
def catch_me(&block)
block.call
end
catch_me { p "I'm in a block" }
# => "I'm in a block!"
So with that in mind, it should be clearer what your Sinatra template is doing - it renders layout.erb but when it hits yield, it tries to yield control to a block - in this case a non-existent one.
So all your responses should supply a block or sub-template like:
erb :layout { "<p>This is the about page</p>" }
or
erb :index
Trying get a handle on oAuth by recreating twitter using the omniauth-twitter and twitter gems, and I'm stuck on viewing the tweets of all the users I'm following in my app together in one place. I can view my own tweets and other users' in their own profile fine.
This is the error trace
NoMethodError in PagesController#home
undefined method `where' for Twitter::Timeline:Class
app/models/twitter/timeline.rb:47:in `from_users_followed_by'
app/models/user.rb:24:in `hub'
app/controllers/pages_controller.rb:5:in `home'
pages_controller.rb
def home
if signed_in?
#hub_items = current_user.hub.paginate(page: params[:page])
end
end
user.rb
def hub
Twitter::Timeline.from_users_followed_by(self)
end
timeline.rb
module Twitter
class Timeline
def self.from_users_followed_by(user)
followed_user_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id"
Twitter::Timeline.where("user_id IN (#{followed_user_ids}) OR user_id = :user_id",
user_id: user.id)
end
end
end
** Controllers
hub_controller.rb
def show
#hub_items = []
render 'pages/home'
end
** Views
_hub.html.erb
<% if #hub_items.any? %>
<ol class="microposts">
<%= render partial: 'shared/hub_item', collection: #hub_items %>
</ol>
<%= will_paginate #hub_items %>
<% end %>
_hub_items.html.erb
<li id="<%= hub_item.id %>">
<% if #hub_item.any? %>
<% #hub_item.each do |post| %>
<% if post.provider == "twitter" %>
<%= render partial: "users/twitter_post", locals: {post: post} %>
<% end %>
</li>
So, Is there a way to write my self.from_users_followed_by method so that it doesn't have to inherit from ActiveRecord::Base? I can give anything else that's needed to figure this out.
Ive had a problem for a couple of days. I've tried every solotion thad i found on stackoverflow, but nothing worked...
Rails gives me an error when i try to add a new 'journey' (just a simple datapase entry): undefined method `journeys_index_path' for #<#:0x3d0b888>
Problem resolved!
The issue was the model name. It was Journeys but it should be journey ! The only thing I had to do is rename the modelfile in app/models. (i had to change the filename and the contents, pretty simple!
Oh and the model name is not the same as the database name.
Please check http://rubyonrailsthrissur.wordpress.com/2012/07/18/naming-conventions-while-creating-tables-in-rails/ for more naming rules
Routes.rb:
Fabulam::Application.routes.draw do
root "home#home"
resources :journeys
match 'auth/:provider/callback', to: 'sessions#create', via: 'get'
match 'auth/failure', to: redirect('/'), via: 'get'
match 'signout', to: 'sessions#destroy', via: 'get', as: 'signout'
end
journeys_controller (relevant part)
def index
#current_user ||= User.find(session[:user_id]) if session[:user_id]
#journey = Journeys.where(uid: current_user.uid)
end
def show
#journey = Journeys.find(params[:id])
end
def new
#journey = Journeys.new
end
new.html.erb (location = journeys/new.html.erb)
<!DOCTYPE html>
<html>
<body>
<div>
<h1> Maak hieronder een nieuwe reis aan! </h1>
<% form_for(#journey) do |f| %>
<p>
<%= f.label :name %><br/<
<%= f.text_field :name %>
</P>
<p>
<%f.submit "Dubmittt" %>
</p>
<% end %>
</div>
</body>
</html>
index.html.erb (location journeys/index.html.erb, this one is working fine)
<!DOCTYPE html>
<html>
<body>
<div id="user_nav">
<% if current_user %>
Signed in as <strong><%= current_user.name %></strong>!
<%= link_to "Sign out", signout_path, id: "sign_out" %>
<% else %>
<%= link_to "Sign in with Facebook", "/auth/facebook", id: "sign_in" %>
<% end %>
</div>
<div id="travels">
Hieronder al je reizen!
<% #journey.each do |journey| %>
<h2><%= link_to journey.name, journey %></h2>
<% end %>
</div>
<p><%= link_to "Add a new journey" , new_journey_path %> </P>
</body>
</html>
Rake routes
Prefix Verb URI Pattern Controller#Action
root GET / home#home
journeys GET /journeys(.:format) journeys#index
POST /journeys(.:format) journeys#create
new_journey GET /journeys/new(.:format) journeys#new
edit_journey GET /journeys/:id/edit(.:format) journeys#edit
journey GET /journeys/:id(.:format) journeys#show
PATCH /journeys/:id(.:format) journeys#update
PUT /journeys/:id(.:format) journeys#update
DELETE /journeys/:id(.:format) journeys#destroy
GET /auth/:provider/callback(.:format) sessions#create
auth_failure GET /auth/failure(.:format) redirect(301, /)
signout GET /signout(.:format) sessions#destroy
Am I missing something?
Thanks in advance!
Have progressed to get wicked_pdf generating PDF's in Rails 3.2.3. However I want to be able to have links on my pages rendered to screen as HTML from the .html.erb file, but when I review the PDF generated from this template I do not want to see these links.
I had tried to follow what Ryan Bates did in is PDFKit Railscast 220, but its not working for me under Rails 3.2.3, on Ruby 1.9.3.
Here is my an abridged section of the view code:
<h2>Client Setup (Only when Patients module is not available)</h2>
<p>
The setup program installs your Clients module using default settings. After the installation, you can use this program to customize settings to meet your particular needs.
</p>
<p>
<%= pdf_image_tag("clients/blank/.png", alt: "Client Setup (Only when Patients Module is not available) - not-populated") %>
<table>
<thead>
<tr>
<th>Form Item</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>Default Value Added Tax (Percent)</td>
<td>
The package offers a default Value Added Tax, expressed as a percentage of the invoice, to be added to the invoice. Numbers from 0 to 999.99 are allowed.
</td>
</tr>
</tbody>
</table>
</p>
<hr />
<form class="form-inline">
Back to Top
<%= link_to "Genie Help Index", help_path, class: "btn btn-main-menu pdf_link" %>
<p id="pdf_link"><%= link_to "Client Help Index", static_page_path("clients/index"), class: "btn btn-help" %></p>
<%= link_to "Download PDF", static_page_path(:format => :pdf), class: "btn btn-pdf" %>
<%= link_to image_tag("file_type_pdf.png", height: "24px", width: "24px" , alt: "Download page as PDF"), static_page_path(:format => :pdf) %>
</form>
<p><%= link_to "Client Help Index", static_page_path("clients/index") %></p>
<p><%= link_to "Download as PDF", static_page_path(:format => "pdf"), class: "pdf_link" %></p>
<p id="pdf_link"><%= link_to "Download as PDF", static_page_path(:format => :pdf) %></p>
<% if request.try(:format).to_s == 'pdf' %>
<%= link_to "Download this PDF", static_page_path(:format => "pdf") %>
<% end %>
#<% if params[:media] = 'all' %>
# <%= link_to "Download me as a PDF", static_page_path(:format => "pdf") %>
#<% end %>
<div id="pdf-no"><%= link_to "Get me as a PDF file", static_page_path(:format => "pdf") %></div>
Controller is: (show page is the name of the page to render)
class StaticPages::GenieHelpController < ApplicationController
def static_page
respond_to do |format|
format.html do
render :template => show_page,
:layout => 'application'
end
format.pdf do
render :pdf => show_page,
:layout => 'generic',
:template => "#{show_page}.html.erb",
:handlers => :erb,
:disable_external_links => true,
:print_media_type => true
end
end
end
end
The layout file in views/layouts/generic.pdf.erb file is as below:
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= wicked_pdf_stylesheet_link_tag "static_pages/genie_v23_help", :refer_only => true %>
<!-- <%#= wicked_pdf_stylesheet_link_tag "static_pages/pdf" %> -->
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div class="container">
<%= yield %>
<%= debug(params) if Rails.env.development? %>
</div>
</body>
</html>
The corresponding css file in old location public/stylesheets/static_pages/genie_help.css:
#media print {
body { background-color: LightGreen; }
#container {
width: auto;
margin: 0;
padding: 0;
border: 2px;
}
#pdf_link {
display: none;
}
}
.pdf_link {
display: none;
}
#pdf-no {
display:none;
}
When I render the html page the links at the bottom show up (as expected) when the format is html.
What am I doing wrong on with this. I assume if it can be done via middleware of PDFKit then it is supported under wkhtmltopdf as both PDFKit and wicked_pdf are based on this.
Thanks
Mark
It turned out to be that I solved this problem by mixing-and-matching the four methods in the wicked_helper.pdf file which is based on the lib helper file.
The wicked_pdf_image_tag was changed to pdf_image_tag used in the pull request waiting commit from - mkoentopf
Multi purpose wicked_pdf_helper "Hi there, I've added some code to the wicked_pdf_helper methods. Now they deliver the the full pa…"
def wicked_pdf_image_tag(img, options={})
if request.try(:format).to_s == 'application/pdf'
image_tag "file://#{Rails.root.join('public', 'images', img)}", options rescue nil
else
image_tag img.to_s, options rescue nil
end
end
What I don't understand is under Rails 3.2 are we still using public directory because sprockets and assests get pre-compiled and placed in public?
The solution I used earlier in the day was to add additional header/footer partials within the html layout, but not in the layout for pdf generation.
Here is the helper file I was using:
module WickedPdfHelper
def wicked_pdf_stylesheet_link_tag(*sources)
options = sources.extract_options!
if request.try(:format).to_s == 'application/pdf'
#css_dir = Rails.root.join('public','stylesheets')
css_dir = Rails.root.join('app','assets', 'stylesheets')
refer_only = options.delete(:refer_only)
sources.collect { |source|
source.sub!(/\.css$/o,'')
if refer_only
stylesheet_link_tag "file://#{Rails.root.join('public','stylesheets',source+'.css')}", options
else
"<style type='text/css'>#{File.read(css_dir.join(source+'.css'))}</style>"
end
}.join("\n").html_safe
else
sources.collect { |source|
stylesheet_link_tag(source, options)
}.join("\n").html_safe
end
end
def pdf_image_tag(img, options={})
if request.try(:format).to_s == 'application/pdf'
image_tag "file://#{Rails.root.join('app', 'assets', 'images', img)}", options rescue nil
else
image_tag img.to_s, options rescue nil
end
end
def wicked_pdf_javascript_src_tag(jsfile, options={})
if request.try(:format).to_s == 'application/pdf'
jsfile.sub!(/\.js$/o,'')
javascript_src_tag "file://#{Rails.root.join('public','javascripts',jsfile + '.js')}", options
else
javascript_src_tag jsfile, options
end
end
def wicked_pdf_javascript_include_tag(*sources)
options = sources.extract_options!
sources.collect{ |source| wicked_pdf_javascript_src_tag(source, options) }.join("\n").html_safe
end
end
It would be good to understand more about how the asset pipeline is used. And how the #media is determined. Is it related to MIME types? If so why do we not need to/or are they not defined in wick_pdf?
I have yet to utilise the page numbering and breaking, but now have an outstanding question that I'll put up separately.