Ruby/Sinatra: Passing a URL variable to an .erb template - ruby

I'm using Padrino, and I want to take parameters out of URL and use them in an .erb template.
In my app setup I have:
get '/testpage/:id' do
userID = params[:id]
render 'test/index'
end
In my test/ folder I have index.html.erb which is successfully rendered, for a url like http://localhost:9000/testpage/hello123.
However, I've tried printing the params[:userID] on the page with:
<%= #userID %>
The rest of the page renders fine but hello123 isn't anywhere to be found. When I try <%= userID %> I get undefined local variable or method `userID' for #<stuff>
What am I missing here?

Just a guess, because I've never used Padrino, but if it works like Rails this may help you:
get '/testpage/:id' do
#userID = params[:id]
render 'test/index'
end

In sinatra, it's just like this (see "Views/Templates" section):
get '/testpage/:id' do |id|
erb :index, :locals => {:id => id}
end
The template is located in views/index.erb by default. It could be change.

Related

Sinatra App Not Using Erb in Links

The problem I'm having is that Sinatra apps don't always seem to show my ERB when it is used in some specific context of hyperlinks. I have no idea how much is relevant to show for this question, so I'll do the best I can .Basically, I have a file in my Sinatra app called book_show.erb. It has the following line:
<p>Edit Book</p>
However, when that link is rendered in the browser, it links like this:
http://localhost:9292/books/#{#book.id}/edit
The #{#book.id} was not replaced with the actual ID value. There is a #book object and I do use it in other contexts in that very same file. For example:
<h1><%= #book.series %></h2>
<h2><%= #book.title %></h2>
<h3>Timeframe:</h3>
<p><%= #book.timeframe %></p>
I don't even know if my routes would make a difference here for diagnosing this but all of the relevant routes for my books functionality are:
get '/books' do
#title = 'Book Database'
#books = Book.all
erb :books
end
get '/books/new' do
#book = Book.new
erb :book_add
end
get '/books/:id' do
#book = Book.get(params[:id])
erb :book_show
end
post '/books' do
book = Book.create(params[:book])
redirect to("/books/#{book.id}")
end
I don't know what else to show to help diagnose this problem. I'm hoping someone sees something terribly obvious that I'm missing.
Adding a book to the database works just fine; it's only that edit link that I can't get to work correctly -- and that would seem to be pure HTML/ERB. In order to test it, I also added this line to the page:
<p>Testing: <%= "/books/#{#book.id}/edit" %>
That came back and returned this text:
Testing: /books/4/edit
So I know the ID is getting stored. It has to be something to do with the hyperlink but I can find nothing useful on Sinatra that helps at all with this.
ERB template does not behave like a ruby string - you need to explicitly tell it you exit the 'template' part into the 'logic' part. It looks very odd when it comes to attributes:
<p>Edit Book</p>
You could use link_to helpers to make it look better:
link_to('Edit Book', controller: 'books', action: 'edit', id: #book.id)

How to implement form_tag helpers without actionview?

I'm working on a Sinatra app and want to write my own form helpers. In my erb file I want to use the rails 2.3 style syntax and pass a block to a form_helper method:
<% form_helper 'action' do |f| %>
<%= f.label 'name' %>
<%= f.field 'name' %>
<%= f.button 'name' %>
<% end %>
Then in my simplified form helper I can create a FormBuilder class and yield the methods to the erb block like so:
module ViewHelpers
class FormBuilder
def label(name)
name
end
def field(name)
name
end
def button(name)
name
end
end
def form_helper(action)
form = FormBuilder.new
yield(form)
end
end
What I don't understand is how to output the surrounding <form></form> tags. Is there a way to append text on only the first and last <%= f.___ %> tags?
Rails has had to use some tricks in order to get block helpers to work as wanted, and they changed moving from Rails 2 to Rails 3 (see the blogposts Simplifying Rails Block Helpers and Block Helpers in Rails 3 for more info).
The form_for helper in Rails 2.3 works by directly writing to the output buffer from the method, using the Rails concat method. In order to do something similar in Sinatra, you’ll need to find a way of writing to the output from your helper in the same way.
Erb works by creating Ruby code that builds up the output in a variable. It also allows you to set the name of this variable, by default it is _erbout (or _buf in Erubis). If you change this to be an instance variable rather than a local variable (i.e. provide a variable name that starts with #) you can access it from helpers. (Rails uses the name #output_buffer).
Sinatra uses Tilt for rendering templates, and Tilt provides an :outvar option for setting the variable name in Erb or Erubis templates.
Here’s an example of how this would work:
# set the name of the output variable
set :erb, :outvar => '#output_buffer'
helpers do
def form_helper
# use the new name to write directly to the output buffer
#output_buffer << "<form>\n"
# yield to the block (this is a simplified example, you'll want
# to yield your FormBuilder object here)
yield
# after the block has returned, write any closing text
#output_buffer << "</form>\n"
end
end
With this (fairly simple) example, an Erb template like this:
<% form_helper do %>
... call other methods here
<% end %>
results in the generated HTML:
<form>
... call other methods here
</form>

String will work but not symbols in Rails

To learn Rails, I am writing a simple guestbook app that does not use a database.
Anyway, this is what my view looks like:
views/guest_book_pages/home.html.erb
<h1>Guest Book</h1>
<%= #userinput %>
<%= form_for(:guestbook) do |f| %>
<%= f.label :input %>
<%= f.text_field :input %>
<%= f.submit "Sign" %>
<% end %>
And the controller looks like this:
controllers/guest_book_pages_controller.rb
class StaticPagesController < ApplicationController
def home
#userinput = params[:guestbook]["input"]
end
end
Whenever I change the "input" to a symbol :input, the application breaks and gives me a warning that says: undefined method `[]' for nil:NilClass
What is the reason for this? Why can't I use a symbol?
update: Now it won't even work with the string. What is going on?
update#2: It works with both symbols and string. The only problem is that it will not load the first time. If I can get the page to load, then either will work. How can I get the page to load?
Action use to be handle something, and render view.
when you inter home, the home action has be called, and no param posted now.
for your code, home action should just be empty, it just to render the home_page.
your handle code should move to some action like sign_in, whitch handle the form post and you can get the params.
The first time you load the page the params var is not set. It is only when you submit your form back that there are params
Try
#userinput = params[:guestbook]["input"] || ''
which will initialize the #userinput to an empty string if the params is not found
edit:
This will check if the params has the key guestbook first, then will either set the instance var userinput to an empty string or the value of [guestbook][input] if it exsists.
If all else fails, the instance var is initialized to an empty string to prevent an error in your view.
if params.has_key?(:guestbook)
#userinput = params[:guestbook]["input"] || ''
else
#userinput = ''
end

Rails Link Helpers not getting localised inside .text.erb files?

I have this action inside a mailer template in Ruby on Rails 3.2:
# password_reset.text.erb
<%= edit_password_reset_path(#user.password_reset_token) %>
Unfortunately, when I hit that link I get a strange routing error:
No route matches {:action=>"edit", :controller=>"password_resets", :locale=>"Ze92D45dUPpfwsgbFmpYeg"}
It is strange that the locale seems to contain the password_reset_token here rather than the locale (e.g. en or de).
So I guess that edit_password_reset_path is not getting localised automatically and that is causing the error?
How could that be fixed?
Here's some more info:
class PasswordResetsController < ApplicationController
def edit
#user = User.find_by_password_reset_token!(params[:id])
end
end
# routes.rb
scope '(:locale)' do
resources :password_resets
....
end
You need to send the token as a query param:
edit_password_reset_path(#user, password_reset_token: #user.password_reset_token)
# Passing in the #user fulfills the :id section of the url.
By doing edit_password_reset_path(#user.password_reset_token) you are providing the reset token to the :locale section.
To provide locale as well:
edit_password_reset_path(#user, locale: "de", password_reset_token: #user.password_reset_token)

Rails helper for Haml

I have a bit of HAML code that gets repeated in something like 10 views and would like to put it into a helper of some kind. Doing a search here produced some interesting results but ultimately no answers, so:
In application_helper.rb I have this:
def pagination_helper(object)
haml_tag :div, :class => 'apple_pagination page_info' do
page_entries_info #book_formats
paginate #book_formats
end
end
In the view template I have this:
- pagination_helper(#book_formats)
If I try calling it with = to output something I get an error.
The above will not give me an error but it won't call the methods either. I get empty divs.
Ultimately the code I want to repeat is this:
.apple_pagination.page_info
= page_entries_info #book_formats
= paginate #book_formats
The code would be the same except the object would change and I send that from the view template. For example #book_formats would change to #dvds, etc.
The block passed to haml_tag doesn’t automatically get added to the output. You need to use haml_concat:
def pagination_helper(object)
haml_tag :div, :class => 'apple_pagination page_info' do
haml_concat(page_entries_info #book_formats)
haml_concat(paginate #book_formats)
end
end

Resources