Set up and modify gem file
rails new formsdemo
gem 'binding_of_caller'
gem 'awesome_print'
gem 'better_errors'
gem 'hirb'
bundle
Make models and define associations
rails generate scaffold items title:string description:string owner:text category_id:integer
rails generate scaffold categories title:string description:string
rails generate scaffold comments from:string message:string item_id:integer
Model changes
# category.rb
has_many :items
# item.rb
belongs_to :category
has_many :comments
Create seed data (seeds.rb)
- Notice an interesting way to create test data
puts "creating categories"
Category.destroy_all
books = Category.create(title: "book", description: "Books, Magazines etc.")
electronics = Category.create(title: "electronics", description: "Computer, Cellphone, etc")
clothing = Category.create(title: "clothing", description: "Shoes, Jackets, Belts, etc")
jewelry = Category.create(title: "jewelry", description: "Rings, watches, necklaces, etc")
owners = ["Jane Smith", "Ira Levin", "George Benson"]
colors = ["red", "brown", "green", "white", "tiny"]
clothingnames = ["shoes", "wallet", "belt"]
adjective = ["My favorite", "The perfect", "A great"]
categories = [books, electronics, clothing, jewelry]
puts "creating sample items"
50.times do
title = colors.sample + " " + clothingnames.sample
description = adjective.sample + " " + title
Item.create(title: title, description: description, owner: owners.sample, category: categories.sample)
end
Create dbs and add seed data
rails db:migrate
rails db:seed
Add Bootstrap
- Notice not using a gem, to keep it simple
- Reference: https://getbootstrap.com/docs/4.0/getting-started/introduction/
- Update views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Formsdemo</title>
<%= csrf_meta_tags %>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<div class="container">
<div class="row">
<%= yield %>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
</body>
</html>
Update the routes
- Notice: how the scategories resource stays flat
- Notice how items > comments is a nested resource
- Notice how the collection is set up
Rails.application.routes.draw do
resources :categories
resources :items do
collection do
get 'search'
get 'do_search'
end
resources :comments, only: [:index, :create]
end
root 'items#index'
end
<div>
<h1>Search</h1>
<%= form_tag(do_search_items_path, method: "get") do %>
<div>
<label>Title</label>
<%= text_field_tag(:title, "") %>
</div>
<%= submit_tag("Search") %>
<% end %>
</div>
And it’s corresponding actions
- Why does search have two actions?
- What controller do these actions go in?
- Notice how to do “like” in order to allow close matches
- Notice how we factor out the index page so we get a parital
#[items_controller.rb]
def search
end
def do_search
@items = Item.where("title LIKE ?", "%#{params\[:title\]}%")
end
#[views/items/_index.html.erb]
<table>
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Owner</th>
<th>Category</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @items.each do |item| %>
<tr>
<td><%= item.title %></td>
<td><%= item.description %></td>
<td><%= item.owner %></td>
<td><%= item.category_id %></td>
<td><%= link_to 'Show', item %></td>
<td><%= link_to 'Edit', edit_item_path(item) %></td>
<td><%= link_to 'Destroy', item, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
#[views/items/index.html.erb\]
<h1>Listing items</h1>
<%= render "index" %>
<br/>
<%= link_to 'New Item', new_item_path %>
Let’s add some Bootstrap
- Bootstrap is already “included” in layouts/application.html.erb
- We bring it to life by adding classes to strategic spots
# [views/items/index.html.erb]
<h1>Listing items</h1>
<%= render "index" %>
<br>
<div class=btn-group %>
<%= link_to 'New Item', new_item_path, class: "btn btn-default" %>
<%= link_to 'Search', search_items_path, class: "btn btn-default" %>
</div>
#[search.html.erb]
<div class="col-md-offset-1 col-md-4">
<h1>Search</h1>
form_tag(do_search_items_path, method: "get", class: "form") do %>
<div class="form-group">
<label>Title</label>
<%= text_field_tag(:title, "", class: "form-control") %>
</div>
<%= submit_tag("Search", class: "btn btn-default") %>
<% end %>
</div>
Now lets add some additional controls
- A drop down control which will allow user to pick search options
# [views/items/search.html.erb]
<div class="form-group">
<label>Return matching or non-matching items</label>
<%= select_tag(:match_no_match,
options_for_select(
\[['only matching', "match"\],
\['only non matching', "nomatch"\]
]), class: "form-control") %>
</div>
#[controllers/items_controller.rb, in do_search\]
def do_search
match_no_match = params.fetch(:match_no_match)
negation = match_no_match == "match" ? "" : " NOT "
query_string = negation + "title LIKE ?"
@items = Item.where(query_string, "%#{params\[:title\]}%")
end