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%>
Related
I have an array:
address => [{"data"=>{"zip"=>"60628", "state"=>"IL", "city"=>"chicago", "street"=>"123 Main St. Apt 2"}, "primary"=>true}]
I want to show each piece in the right format on my view like:
123 Main St. Apt 2
Chicago, IL 60628
I am having trouble getting the logic correct to show this.
Where should this logic go, as a method in my model or in the actual view?
I tried:
<% #applicant.address.map{|x| x[:data]}.each do |address| %>
<%= address.street %><br><%= address.city %>, <%= address.state %> <%= address.zip %> <br>
<% end %>
but got:
=> [{"zip"=>"60628", "state"=>"IL", "city"=>"chicago", "street"=>"123 main st Apt 2"}]
The map gives you a new array and if you use hashes you need to access the values with the hash[:key] or hash["key"] operator, try this:
<% #applicant.address.each do |address_hash| %>
<% address = address_hash["data"] %>
<%= address["street"] %><br><%= address["city"] %>, <%= address["state"] %> <%= address["zip"] %> <br>
<% end %>
But if I were you , I'd put the data in an array of structs, it's more readable.
In your model or helper:
address = Struct.new(:street, :city, :state, :zip)
address.street = ..
...
#addresses << address
etc
In your view:
<% #addresses.each do |address| %>
<%= address.street %><br><%= address.city %>, <%= address.state %> <%= address.zip %> <br>
<% end %>
For your first question something like this should suffice:
#!/usr/bin/env ruby
require 'ostruct'
address = [
{
'data' => {
'zip' => '60628',
'state' => 'IL',
'city' => 'chicago',
'street' =>'123 Main St. Apt 2'
},
'primary' => true
}
]
class AddressPresenter
def initialize(address)
#address = OpenStruct.new(address)
end
def to_s
"#{#address.street} \n#{#address.city} #{#address.state} #{#address.zip}"
end
end
address.each do |a|
puts AddressPresenter.new(a['data'])
end
Now, for the second question, I would implement a Presenter class whose only goal is to "present" the data in whatever format you need in the view, this allows you to keep your views with 0 presentation logic. So in this case the class AddressPresenter could be reworked to return in the to_s the right HTML you need in your view. And you would do something like:
<% #applicant.address.each do |address| %>
<%= AddressPresenter.new(address['data']).to_s %>
<% end %>
By having a separated presenter class, you get the following benefits:
Your models don't worry about how to present/render stuff because that's not their job
You can test this presenter to confirm it returns whatever you're expecting in the view
Your views don't contain any complicated logic
I'm trying to make a basic search function for a simple product inventory app on Sinatra, but don't know how to make the controller and view to properly output all the products which have similar names to a results page.
SearchPage.erb:
<form action="/search", method="post">
<input type="text" name="product[name]">
Controller:
post '/search' do
#Products = Product.find_by(name: params[:product][:name])
#Products = Product.all(:name.like => "%#{params[:name]}%") #found this on another question
erb :"result"
end
Result.erb
<% #Products.each do |product| %>
<%=product.name %>
<%=product.details %>
EDIT: I was able to make search work based on the suggestion with the following code. Thanks!:
Search.erb View
<form action="/search", method="get">
<input type="text" name="search">
Controller
get '/search' do
#products = Product.all
if params[:search]
#products = Product.search(params[:search])
else
#products = Product.all
end
erb :'results'
end
Model
class Product < ActiveRecord::Base
def self.search(search)
where("name like ?", "%#{search}%")
end
Results.erb View
<% if #products.present? %>
<table>
<td>Product Name</td><td>Company</td>
<% #products.each do |product| %>
<tr><td><%=h product.name %> </td>
<td><%=h product.company.name %></td>
<% end %>
<% else %>
<p>There are no Products containing the term(s) <%= params[:search] %>.</p>
<% end %>
</table>
I notice off the bat you're using a POST method. There is an easier way to do create search functionality for your products. Try this:
Posts Controller:
#products = Product.all
if params[:search]
#products = Product.search(params[:search]).order("created_at DESC")
else
#products = Product.all.order('created_at DESC')
end
end
Posts Model (note: If you are using SQLite keep it as LIKE. If you are using Postgres, change LIKE to ILIKE)
def self.search(search)
where('name like :pat or content like :pat', :pat => "%#{search}%")
end
Search Form (Put into your Result.erb and edit as needed but keep as get method. I personally like using form helpers but you can create a normal form if you'd like)
<%= form_tag(products_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :search, params[:search], placeholder: "Search Posts" %>
<%= submit_tag "Search" %>
<% end %>
Render Results
<% if #products.present? %>
<%= render #products %>
<% else %>
<p>There are no posts containing the term(s) <%= params[:search] %>.</p>
<% end %>
Let me know if this works for you. If not, i'll try help some more.
I have a form to fill in booking details, but I'm getting the following error:
NoMethodError in Bookings#new
undefined method `bookings_path'
This happened after change the routes.rb file, to nest the booking resources in the user resource.
My form file code is the following:
<% provide(:title, 'Book Now!') %>
<section id="book-now">
<%= form_for(#booking) do |f| %>
<header>
<h1>Edit booking</h1>
</header>
<%= f.text_field :name, placeholder: "Name" %>
<%= f.text_field :check_in, placeholder: "Check-in" %>
<%= f.text_field :check_out, placeholder: "Check-out" %>
<%= f.submit "Save" %>
<% end %>
</section>
My booking controller code is:
class BookingsController < ApplicationController
def new
#booking = Booking.new
end
def create
#booking = Booking.new(params_bookings)
#booking.user_id ||= current_user.id
if #booking.save
redirect_to user_path(#booking.user_id)
else
# render 'new'
end
end
end
private
def params_bookings
params.require(:booking).permit(:check_in, :check_out, :name, :user_id)
end
end
and my routes.rb file looks like this:
Hightide::Application.routes.draw do
resources :users do
resources :bookings
end
match '/users/:user_id/bookings/new', to: 'bookings#new', via: [:post, :get]
you have this error because your bookings routes are nested to the users, so when you write this
form_for #booking
you essentially call
form_for bookings_path, ...
coz rails gets the type of the object you send to form_for and tries to get vanilla path for it.
to solve the problem you need either create the vanilla bookings resources in your routes, or specify both a user and a booking reference for the form_for call, like so
form_for [current_user, #booking]
I'm creating a web application with formtastic. I installed the gem and wrote my code like this:
<%= semantic_form_for #index do |form| %>
<%= form.inputs do %>
<%= form.input :name %>
<%= form.input :born_on, :start_year => 1997 %>
<%= form.input :description, :as => :text %>
<%= form.input :female, :as => :radio, :label => "Gender", :collection => [["Male", false], ["Female", true]] %>
<% end %>
<%= form.actions do %>
<%= form.action :submit, :as => :button %>
<% end %>
<% end %>
I want the form to appear on the index page which is why I have #index. For some reason I can't do #index. How would I reference the top line so that it renders a form on the index page? Currently my index page has nothing in it, but it is defined in the controller
form_for helper expects some object that responds to fields You refer inside Your form. Here is an example of using semantic_form_for with plain Ruby object: http://affy.blogspot.com/2010/02/using-formtasic-without-activerecord.html.
Also the object You specify for form doesn't effect which page is being rendered. Are You sure You are not mixing up something? Maybe if You share a bit more of Your controller code we might help You better.
I am making a super small Sinatra blog application, how could I take entries from a database, format them, and insert them into my layout?
class Blog < Sinatra::Base
helpers do
def partial (template, locals = {})
erb(template, :layout => false, :locals => locals)
end
end
get "/list" do
#posts = Post.all
erb :list
end
end
list.erb:
<% #posts.each do |post| %>
<%= partial(:post, :post => post) %>
<% end %>
post.erb:
<h1><%= post.title %></h1>
<p><%= post.body %></p>
<% #posts.each do |post| %>
<%= erb :"_partial_name", :locals => {} %>
<% end %>
the partial template need start with _