Ruby学习笔记6: 动态web app的建立(3)--多Model之间的交互
We first built a static site which displayed a static image using only a Controller and a View. This is our Etsy landing page page.
Then we built the Categories page, with a Model (manages data), Controller (manages decisions) and View (manages display). The Categories pages allows us to display dynamic content so users can browse through different Categories that can be updated regularly.
Now we will build the Products page, which will allow users to browse through Products in our Etsy app. To create this, we'll be creating a new Model, Controller, and View.
Now, because have more than one Model, we will also learn how Models interact with each other through associations.
前面我们完成的ruby on rails app 的静态、动态网页开发,实现了数据库增删改查的操作,熟悉了MVC结构的工作机理。本文在前面的基础上,要新增一个Prodect的Model,从而体现多model交互的功能。
====================================
Product Page 的效果如下:
Let's review our Request-Response Cycle one more time.
Again, in our Products page, we're using a database just like we did for Categories.
- Our browser will first make a request to the server. The server handles the requests by talking to our Rails application.
- Second, the route takes the request and finds the right Controller and method to handle the request.
- Third, the Controller gathers data directly from our Model. It assembles the data in methods and then passes it on the View.
- Finally, the View packages the information and sends it back to our browser.
Request-Response Cycle的工作机理:
1. 浏览器发送请求到服务器,服务器处理请求,怎么处理:跟Rails App 说:有个请求来了!
2. the routes 拿到请求,找到正确的Controller和Method,来处理这个请求。
3. Controller 开始收集数据,从Model里收集,在Methods里组装数据,完了就传递给View
4. 最后,View把所有的信息打包好,包括数据,样式,文本,图片各种。。。传回给浏览器。
========================================
下面开始我们Making Product Page
This page will list all products that users buy - like shoes or craft paper. Users will be able to browse through products and find what they like.
When we created a Model for Categories, we were able to add information about our categories. For Products, we will also create a Model so we can add information about our products, such as a product name or price.
1. Generate the product model
we generate a model like this:(in terminal)
rails generate model product
Remember that Model names are always singular.
When we generate a Product Model, we create corresponding Model and Migration files. Let's first focus on the product model.
2. build the association between two models
Since we have more than one Model, a Category Model and a Product Model, we can build the association between the two.
Why do we need associations? As you create the Etsy app, you want to make sure that certain Products are associated with a Category. What if we want to put our painting in the Art category, or a toy in the Kids category?
Associations do just this. They tell us how parts of our app relate to other parts.Association(关联)就是解决我们app的一些parts和另一些parts 是怎么个关系。
How do we create associations? The most basic type is a has_many and belongs_to relationship, where 'one thing' has many 'other things'. Imagine a Person and their Pets. The Person has_many Pets, and Pets belongs_to the Person.怎么来创建一个关联呢?
最基本的类型就是 has_many 和 belongs_to 关系。has_many 就是 ‘一个东西’ 有很多 ‘其他东西们’ ,设想,一个人和他的宠物们。就是这个人has_many 宠物们,并且,宠物们 belongs_to 这个人。
In the Person Model we type:
class Person
has_many :pets
end
In the Pet Model, we type:
class Pets
belongs_to :person
end
In our case, our Category has many products, and Product belongs to category:
class Category
has_many :products
end
In the Pet Model, we type:
class Products
belongs_to :category
end
**app/models/category.rb:
class Category < ActiveRecord::Base
has_many :products
end
同时,
**app/models/product.rb:
class Product < ActiveRecord::Base
belongs_to :category
end
3. prepare our Products Migration table
Now that our Product Model is set up, we need to prepare our Products Migration table so that it has the right columns.
If you recall from the Categories Migration, we do this in two steps:
a. Add columns to our Products Migration table
b. Type bundle exec rake db:migrate in the terminal
In this case, there's one more column that we will add. Now that we have an association, we need to tell our Models that our Product Model belongs to our Category Model by adding areferences column.
we had a Product that belonged to a Category, we would add t.referencesto ourPet table to look like this:
in our Products Migration table, we will :references to Category. We always add references to the table thatbelongs_to something else.[从model里添加references to 主model.] 这里我们就是产品model的文件里,Reference to Category, buz product model belongs
to category model.
1. 文件**db/migrate/20140626211017_create_products.rb:
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :product_name #string
t.text :description #text
t.float :price #float
t.string :thumburl #string
t.references :category #references
t.timestamps #timestamps is required.
end
end
end
2. In terminal, run bundle exec rake db:migrate to migrate your database. Press Enter.
$ bundle exec rake db:migrate
== 20140626211017 CreateProducts: migrating ===================================
-- create_table(:products)
-> 0.0013s
== 20140626211017 CreateProducts: migrated (0.0013s) ========================== $
4. Add seed data for our Products
Now that we have columns, let's add seed data for our Products. If you recall there are also two steps for this:
a. We add seed data in our seeds.rb file
b. We run
rake db:seed in the terminal (bundle exec rake db:seed)
We already added most of the Products seed data for you. This time with one small change. Since each product belongs to a specific category, we'll also be adding a category_id at the end for art.
Let's look at some seed data:
Product.create(product_name: 'Spanish Canvas Painting', description: 'La Fuente de Monteforte Painting Acrylic', price: 79.00, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/e/eb/144-la_fuente_de_Monforte_V.jpg', category_id: art.id)
As we can see, each of our Product columns has an entry. We also have
category_id: art.id, referencing that this product belongs to the art category.
** db/seeds.rb:
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first) art = Category.create(name: 'Art', thumburl: 'http://upload.wikimedia.org/wikipedia/commons/e/eb/144-la_fuente_de_Monforte_V.jpg')
home_and_living = Category.create(name: 'Home & Living', thumburl: 'http://ihomedecorsideas.com/wp-content/uploads/2014/04/diy_network_homemade_coat_rack_.jpg')
jewelry = Category.create(name: 'Jewelry', thumburl: 'http://upload.wikimedia.org/wikipedia/commons/f/ff/Midyat_Silver_Jewelry_1310103_Nevit.jpg')
women = Category.create(name: 'Women', thumburl: 'https://c1.staticflickr.com/9/8255/8660920433_57a184d9d1_z.jpg')
men = Category.create(name: 'Men', thumburl: 'http://upload.wikimedia.org/wikipedia/commons/d/d5/Fullbrogue_(Grenson).jpg')
kids = Category.create(name: 'Kids', thumburl: 'http://upload.wikimedia.org/wikipedia/commons/e/e0/Artist%27s_Paint_Brushes_Adapted_With_Photoshop._Surrey_UK.jpg')
vintage = Category.create(name: 'Vintage', thumburl: 'https://c2.staticflickr.com/8/7402/9426557291_139134efaa_z.jpg')
weddings = Category.create(name: 'Weddings', thumburl: 'http://hostingessence.com/wp-content/uploads/2012/04/green-wedding.jpg')
craft_supplies = Category.create(name: 'Craft Supplies', thumburl: 'http://bit.ly/1w1uPow') #Art
Product.create(product_name: 'Russian Acrylic', description: 'Acrylic on Canvas', price: 59.00, thumburl: 'http://bit.ly/1nDkJZw', category_id: art.id) Product.create(product_name: 'Spanish Canvas Painting', description: "La Fuente de Monteforte Painting Acrylic", price: 79.00, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/e/eb/144-la_fuente_de_Monforte_V.jpg',
category_id: art.id)
Product.create(product_name: 'French Acrylics & Pastel Canvas', description: "Jeanne d'Arc Arrivant a l'ile Bouchard", price: 122.00, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/3/36/2004_Yuri-Yudaev_Before-the-City-Gate_Acrylic-on-canvas_40x40cm.jpg', category_id: art.id) # Home & Living Product.create(product_name: 'Art Deco Glass', description: "Before-the-City-Gate Acrylic-on-canvas", price: 1599.00, thumburl: 'http://ihomedecorsideas.com/wp-content/uploads/2014/04/diy_network_homemade_coat_rack_.jpg', category_id: home_and_living.id)
Product.create(product_name: 'Rustic Homemade Coatrack', description: "Coatrack made of Maple Tree Branches", price: 288.00, thumburl: 'https://c2.staticflickr.com/6/5308/5821079295_4580e3c8d3_z.jpg', category_id: home_and_living.id)
Product.create(product_name: 'Forest Wood Coffee Table', description: "Chista Natural Wood Rustic Collection", price: 299.00, thumburl: 'https://c1.staticflickr.com/3/2777/4033647409_3c04157d86.jpg', category_id: home_and_living.id) # Jewelry Product.create(product_name: 'Vintage Rhinestone Earrings', description: "Lightweight Rhinestone Earrings in Sterling Silver Setting", price: 9.00, thumburl: 'http://fc03.deviantart.net/fs70/f/2011/340/0/5/dangle_ear_rings_stock_png_by_doloresdevelde-d4idyev.png', category_id: jewelry.id)
Product.create(product_name: 'Moon Turquoise Ring', description: "Mediyat Silver" , price: 39.99, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/f/ff/Midyat_Silver_Jewelry_1310103_Nevit.jpg', category_id: jewelry.id)
Product.create(product_name: 'Greek Gold Necklace', description: "Greek Gold Plated Necklace", price: 4570.00, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/0/02/Ancient_greek_jewelry_Staatliche_Antikensammlungen_Room_10_06.jpg', category_id: jewelry.id) # Women Product.create(product_name: 'Chloe Frill Yellow Dress' , description: "Vintage yellow dress with floral design. Lightweight with frill on skirt.", price: 59.99, thumburl: 'https://c1.staticflickr.com/9/8255/8660920433_57a184d9d1_z.jpg', category_id: women.id, )
Product.create(product_name: 'Autumn Knitted Sweater with Silver Buttons', description: "Knitted Crop Sweater with Silver Buttons", price: 45.99, thumburl: 'https://c2.staticflickr.com/4/3049/2353463988_c9d8cde436_z.jpg?zz=1', category_id: women.id)
Product.create(product_name: 'Rucksack', description: "Rucksack Schweizer Armee 1960.", price: 39.99, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/a/a1/Image-2D_and_3D_modulor_Origami.jpg', category_id: women.id) # Men Product.create(product_name: 'Grenson Shoes', description: "Fullbrogue Grenson Shoes.", price: 105.00, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/d/d5/Fullbrogue_(Grenson).jpg', category_id: men.id)
Product.create(product_name: 'Color Fringed Scarf', description: "Men’s Fringed Scarf in Pumpkin Toffee Grey.", price: 19.99, thumburl: 'https://c2.staticflickr.com/4/3437/3832752067_c6c3631d44_z.jpg?zz=1', category_id: men.id)
Product.create(product_name: 'Pork Pie Hat', description: "Classic Pork Pie Hat from the 1940s.", price: 110.00, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/0/05/Brown_Porkpie_Hat.JPG', category_id: men.id) # Kids Product.create(product_name: 'Peruvian Hats', description: "Handmade Peruvian Winter Hats for Children.", price: 15.00, thumburl: 'https://c2.staticflickr.com/8/7020/6498656815_3937483e21_z.jpg', category_id: kids.id)
Product.create(product_name: 'Norev Toy Car', description: "Classic Norev Model Toy Car for Children", price: 17.00, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/6/61/Norev_4cv.jpg', category_id: kids.id)
Product.create(product_name: 'Stickle Bricks', description: 'Toy Stickle Brick Building Blocks Set', price: 21.99, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/f/f1/Stickle_bricks.jpg', category_id: kids.id) # Vintage Product.create(product_name: 'Anders Brown Leather Bag', description: "Vintage Leather with White Trim.", price: 79.99, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/3/3d/Gesellenst%C3%BCck_Lederhandwerk.jpg', category_id: vintage.id)
Product.create(product_name: 'Cambridge Red Footsies', description: "Red Vintage Leather Shoes Children with Brown Laces and White Trim", price: 45.99, thumburl: 'https://c1.staticflickr.com/3/2587/3797274851_8199f17d01.jpg', category_id: vintage.id)
Product.create(product_name: 'Voightlander Camera', description: "Voightlander Vintage Camera with Metal Case", price: 179.00, thumburl: 'http://upload.wikimedia.org/wikipedia/commons/6/67/A_vintage_Voigtl%C3%A4nder_Vito_B_camera.jpg', category_id: vintage.id) # Weddings Product.create(product_name: 'Green Wedding Decor', description: "Forest Dream Wedding Decoration Ideas", price: 27.00, thumburl: 'http://hostingessence.com/wp-content/uploads/2012/04/green-wedding.jpg', category_id: weddings.id)
Product.create(product_name: 'Embossed Soap Wedding Favors', description: "Lavendar Handmade Soap decorated with elegant nature design. ", price: 4.50, thumburl: 'https://c1.staticflickr.com/1/203/518233215_cb4d2af38f_z.jpg?zz=1', category_id: weddings.id)
Product.create(product_name: 'Handmade Centerpieces', description: "Handmade Wedding Tea Cup Centerpieces for Your Guests", price: 35.00, thumburl: 'http://indiefixx.com/wp-content/uploads/2011/06/GR_teacupcenterpieces.jpg', category_id: weddings.id) # Craft Supplies Product.create(product_name: 'Korean Indasong Craft Paper', description: "Origami Paper Kit", price: 17.00, thumburl: 'http://commons.wikimedia.org/wiki/File:Vesta_sewing_machine_IMGP0718.jpg', category_id: craft_supplies.id)
Product.create(product_name: 'Handmade Gift Wrap', description: "Esoterica Handmade Supplies", price: 14.00, thumburl: 'http://commons.wikimedia.org/wiki/File:Vesta_sewing_machine_IMGP0718.jpg', category_id: craft_supplies.id)
Product.create(product_name: 'Lollipot Flavor Kit', description: "Flavor Kit for Celebration Lollipops and Gifts", price: 21.00, thumburl: 'http://commons.wikimedia.org/wiki/File:Vesta_sewing_machine_IMGP0718.jpg', category_id: craft_supplies.id)
In terminal type: bundle exec rake db:seed
$ bundle exec rake db:seed
$
$ bundle exec rake db:seed
$
Now that we have a Model, we can create our Products Controller and Views. The Controller methods ensure that we serve dynamic content to the Products View. We can change the information users see.
5. Create our Controller
We saw this diagram when we created our Categories Controller. The good news is that our Products Controller will use the same pattern. We will use Create, Read, Update, and Delete to change information, commonly called CRUD.
Remember that five of these methods, index, show, new, edit, delete have Views as indicated here.
Take a look at the image below. It lists the Create, Read, Update, and Delete methods and what they do.
我们有Model了,要建立Products 的Controller,跟Category一样。
我们要Products页面是动态的,包含8个methods, This way, we can 改变我们products的信息。
我们就从5个有对应view的methods开始。在Terminal里:
rails generate controller products index show new edit delete
Here we list the five main methods that have Views.
$ rails generate controller products index show new edit delete
create app/controllers/products_controller.rb
route get 'products/delete'
route get 'products/edit'
route get 'products/new'
route get 'products/show'
route get 'products/index'
invoke erb
create app/views/products
create app/views/products/index.html.erb
create app/views/products/show.html.erb
create app/views/products/new.html.erb
create app/views/products/edit.html.erb
create app/views/products/delete.html.erb
invoke test_unit
create test/controllers/products_controller.rb
invoke helper
create app/helpers/products_helper.rb
invoke test_unit
create test/helpers/products_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/products.js.coffee
invoke scss
create app/assets/stylesheets/products.css.scss
$
**app/controllers/products_controller.rb文件里,接下来就要写methods了。
6. Add the method keep our data secure
We'll need to give our Products a secure way of fetching information from our Model.
We'll create a strong parameters method that will keep our data secure. This private method prevents someone from altering the information we store in our Product Model.
**app/controllers/products_controller.rb文件里,加入:
private
def product_params #strong params method, based on the name of the Model: 'product'
params.require(:product).permit(:product_name, :description, :price, :thumburl)#requires the Model name, and permits the columns
end
As you can see a strong params method (i.e. product_params) will be based on the name of the Model. Here, params requires the Model name (product) and permits the columns stored in our Migration table (product_name, description, price and thumburl).
7. Add the main controller methods: index, show, new, edit and delete
Now it's time to create our main controller methods again: index, show, new, editand delete. Lucky for us, Rails is built on a series of patterns. We'll be using many of the same patterns we used before!
三个文件:
1. Controller: app/controllers/products_controller.rb
2. Routes: config/routes.rb
3. Views:
index: app/views/products/index.html.erb
show: app/views/products/show.html.erb
new: app/views/products/new.html.erb
edit: app/views/products/edit.html.erb
delete: app/views/products/delete.html.erb
=========
>> 先准备好Routes: config/routes.rb
----
Rails.application.routes.draw do
get '/' => 'pages#home' resources :categories
get 'categories/:id/delete' => 'categories#delete', :as => :categories_delete #this takes care of our main controller routes for products
resources :products
get 'products/:id/delete' => 'products#delete', :as => :products_delete
end
----
>> 再一个个写Controller和Views
7.1 For index:
Controller:
----
define index
@products = Product.all
end
----
View:
----
<h1>Listing products</h1> <table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Price</th>
<th>Thumburl</th>
<th colspan="3"></th>
</tr>
</thead> <tbody>
<% @products.each do |product|%>
<!--# iterate through @products %>-->
<tr>
<td><%= product.product_name%></td>
<td><%= product.description %></td>
<td><%= product.price %></td>
<% if product.thumburl %>
<%= image_tag product.thumburl %>
<% end %>
<td><%= link_to 'Show', product %></td>
<td><%= link_to 'Edit', edit_product_path(product) %></td>
<td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table> <br> <%= link_to 'New Product', new_product_path %>
We're getting closer! The index page you made has all the right information, but this time around we added some style to the page. It now includes the supporting HTML for your Views.
Let's try adding the index view for categories again, now with style. Here again we would iterate through all Products and print out the name and the thumburl.
**文件
<%= render 'shared/topnav' %>
<br>
<br>
<br> <h1>Listing products</h1> <% @products.in_groups_of(3).each do |products| %>
<% products.select! {|x| !x.nil?} %>
<div class='row'>
<% products.each do |product| %>
<div class='col-md-4'>
<div class="thumbnail">
<img src= <%= product.thumburl %> >
<div class="caption">
<span class="listing-title"><%= product.product_name %></span>
<span class="listing-desc"><%= product.description %></span>
<span class="listing-price"><%= number_to_currency(product.price) %></span>
<span><%= link_to "Edit", edit_product_path(product.id) %></span>
<span><%= link_to "Delete", products_delete_path(:id => product.id) %></span>
</div>
</div>
</div>
<% end %>
</div>
<% end %>
<br> <%= link_to 'New Product', new_product_path %> <%= render 'shared/footer' %>
7.2For show method
The show method finds an object by its id, and stores it in @product. Let's create the show method in our controller. Using our Pet example, it looks like this:
def show #request: localhost:8000/products/1
@product = Product.find(params[:id])
end
We still need a view! We just want to show one product on a page. Let's go ahead and make the view for show.
To do this, we'll be printing out the attributes that we stored in our instance variable @product. We add . and the attributes name after each attribute we print out.
***app/views/products/show.html.erb:
<p>
<strong>Product name:</strong>
<%= @product.product_name%>
</p> <p>
<strong>Description:</strong>
<%= @product.description %>
</p> <p>
<strong>Price:</strong>
<%= @product.price %>
</p> <p>
<strong>Thumburl:</strong>
<%= @product.thumburl%>
</p> <%= link_to 'Edit', edit_product_path(@product) %> |
<%= link_to 'Back', products_path %>
7.3 Prepare _form.html.erb file
在准备接下来的new/edit method之前,我们还需要准备好 _form.html.erb 文件:app/views/products/_form.html.erb
<%= form_for(@product) do |f| %> <div class="product_name">
<%= f.label :productname %><br> <!--为什么这里不能有空格呢?-->
<%= f.text_field :product_name %>
</div>
<div class="description">
<%= f.label :description %><br>
<%= f.text_field :description %> </div>
<div class="price">
<%= f.label :price %><br>
<%= f.text_field :price %> </div>
<div class="thumburl">
<%= f.label :thumburl %><br>
<%= f.url_field :thumburl %> </div>
<div class="actions">
<%= f.submit %> </div>
<% end %>
7.4 Create the new method
*** app/controllers/products_controller.rb :
def new #localhost:8000/products/new
@product = Product.new
end
def create
@product = Product.new(product_params)
if @product.save
redirect_to(:action => 'index')
else
render('new')
end
end
View: ***file: app/views/products/new.html.erb
<%= render 'shared/topnav' %> <h1>New Product</h1> <!-- Render form here -->
<%= render 'form' %> <%= link_to 'Back', products_path %> <%= render 'shared/footer' %>
7.5 Create the edit method
def edit #localhost:8000/products/1/edit
@product = Product.find(params[:id])
end
def update
@product = Product.find(params[:id])
if @product.update_attributes(product_params)
redirect_to(:action => 'show', :id => @product.id)
else
render('index')
end
end
View: app/views/products/edit.html.erb
<%= render 'shared/topnav' %> <h1>Edit Product</h1> <!-- Render form here -->
<%= render 'form' %> <%= link_to 'Back', products_path %> <%= render 'shared/footer' %>
7.6 Create the delete method
def delete
@product = Product.find(params[:id])
end def destroy
Product.find(params[:id]).destroy
redirect_to(:action => 'index')
end
View: ** app/views/products/delete.html.erb
<p>
<strong>Product name:</strong>
<%= @product.product_name %>
</p> <p>
<strong>Description:</strong>
<%= @product.description %>
</p> <p>
<strong>Price:</strong>
<%= @product.price %>
</p> <p>
<strong>Thumburl:</strong>
<%= @product.thumburl %>
</p> <%= link_to 'Delete', products_delete_path(:id => @product.id) %> |
<%= link_to 'Edit', edit_product_path(@product) %> |
<%= link_to 'Back', products_path %>
8. Conbine two Models together
Before we finish, one final piece remains. We have a Products page and a Categories page, but right now they live entirely separate from one another.
Instead, we want our users to be able to go to a Category, click on show, and access the Products in that Category. If a user clicks on show in the Art Category, we should see the Art products that belong here.
We can do this by nesting嵌套 Products in our Categories show method. Since we have an association, we can list out all the products that belong to that category.
为了让我们点击art这个category的show时,可以列出在art下的所有product,也就是要让product 按 art 分类。此时我们要把Products嵌套在Category下面,我们已经有association了,所以可以list out all the products that belong to that category.
*** app/controllers/categories_controller.rb
def show
@category = Category.find(params[:id])
@products = @category.products #new code we write, this works cuz we hava an association
#store the products of a given category in an instance variable @product
end
Here @products = @category.products is the new code we write. This works because we have an association. Our code knows that certain products belong to a Category. We mentioned that Category
in our seed data. 这里好玄乎啊!我们的代码知道某个产品是属于哪个category的,在我们的seed data里,我们提到了那个product所属的Category. 牛!所以,我们就加了这行代码,从而:In categories_controller.rb, in the Categories show method, add code to store the products of a given category
in an instance variable @product.
除了嵌套Controller,还要嵌套nesting Views:
The last and final step is to change the View for Categories show to be our Products index. This is because Categories show should now have all the Products for that Category.
Good news. We already wrote the code for this. All we need to do is pass it into a file. We can actually go ahead andreplace the code we wrote for Categories show, with the code for Products index.我们已经有了products & categories的view,所以我们要做的是把它们pass
into到一个file里。直接把Category show的代码替换成code for the Products index.
[Instructions:]
>>Copy all the code from your Products index in index.html.erb and paste it into your Categories show View in show.html.erb. All your previous code in Categories show can be replaced. 把”app/views/products/index.html.erb“中的代码,全部替换到”app/views/categories/show.html.erb“中,”app/views/categories/show.html.erb“中的代码可以不要了。
>>In your browser, visit localhost:8000/categories. On the Index page, under Art, click on Show. This will now show the Art Products in that Category.
但是好像有点问题。点了没有列出art下面的所有东东。去到了一个categories/1
==========================
Congratulations! You created the Products page of the Etsy app. We created the Model, Controller, and Views for Products.
We generated the Product Model using our terminal. We used associations to define the relationship between the Category and Product table. We added Migration columns and migrated and seeded our database.
We then generated a Products Controller with the index, show, new, edit, and delete methods. This gave us route and View for those methods.
We created Controller methods for all eight of our CRUD actions, and Views for index, show, new, edit, and delete. We also nested our Products in our Categories show View.
Nice job. Now we'll finish our Etsy app by adding Authentication.
Ruby学习笔记6: 动态web app的建立(3)--多Model之间的交互的更多相关文章
- Ruby学习笔记4: 动态web app的建立
Ruby学习笔记4: 动态web app的建立 We will first build the Categories page. This page contains topics like Art, ...
- Ruby学习笔记5: 动态web app的建立 (2)
上一节里,我们搭建了一个数据库的结构,并用index验证了request-response cycle,如下图: 1. Add show method into Controller 这一节,我们要继 ...
- JavaWeb学习笔记——开发动态WEB资源(一)Java程序向浏览器输出数据
开发一个动态web资源,即开发一个Java程序向浏览器输出数据,需要完成以下2个步骤: 1.编写一个Java类,实现Servlet接口 开发一个动态web资源必须实现javax.servlet.Ser ...
- JavaWeb学习笔记——开发动态WEB资源(八)cookies和httpsession
会话: cookies: (1)cookies是WEB服务器发送到浏览器的简短文本信息 (2)cookies可以禁用 httpsession: 一次会话是从你打开浏览器开始到你关闭浏览器结束 提供一种 ...
- JavaWeb学习笔记——开发动态WEB资源(六)ServletConfig和ServletContext
1.只有在第一次请求服务器产生实例的时候才会调用init()方法,有一种办法能在服务器一启动的时候就加载init()方法. 即服务器启动即加载Servlet,且按数字大小顺序实例化Servlet. 方 ...
- JavaWeb学习笔记——开发动态WEB资源(五)servlet身份验证
本工程的功能是实现Javaweb的servlet身份验证 一下是login.html文件中的代码 <!DOCTYPE html> <html> <head> < ...
- JavaWeb学习笔记——开发动态WEB资源(四)打印当前使用的是get方法
该工程的名称是testhttp,功能是在页面中表格打印浏览过程中的相关头信息. 新建一个工程,然后在这个工程里面新建一个servlet,这样便可以省去编写web.xml的过程 以下是TestHttpS ...
- JavaWeb学习笔记——开发动态WEB资源(三)显示当前时间
该工程的功能是实现在页面中显示当前的时间 以下的代码是HelloServlet.java中的代码 package helloapp2; import java.io.IOException; impo ...
- JavaWeb学习笔记——开发动态WEB资源(二)HelloWord
该工程的功能是在页面上输出一段话 首先在src里面新建一个class,在interface里面添加javax.servlet.Servlet 以下是HelloServlet.java中的代码: pac ...
随机推荐
- Google program AB程序的基本理解
这个是2017年机器人项目中涉及到的一点东西,虽然没有派上什么大用场,但是还是有必要在这里记录一下! 1. 初始化Bot A. 配置各种路径,例如aiml,aimlif,config,set,map等 ...
- 【java】对象赋值给另一个对象
对基本数据类型的赋值很简单的.基本类型存储了实际的数值,而并非指向一个对象的引用,所以在赋值的时候,是直接将一个地方的内容复制到另一个地方.对于a=b,修改b后并不会影响到a,这正是我们大多数情况下所 ...
- eval 日期对象
js中,eval相当于python中的eval(表达式)和exec(代码)的集合. var d = new Date(); #申明一个新的日期对象,方便之后调用,它的方法getDate();ge ...
- xe5 android 控制蓝牙[转]
用以下代码中的接口实现控制蓝牙的开.关及详细信息 unit Androidapi.JNI.BluetoothAdapter; // (c) RedTitan Technology 2013// JNI ...
- python3学习笔记一(标识符、关键字)
查看Python版本 可以命令窗口,windows使用win+R调出cmd运行框,输入以下命令: python -V 进入python的交互编辑模式,也可查看 D:\Python3.6\Scripts ...
- react中的路由模块化
在vue中,可以将路由单独写在一个配置文件中,便于整理维护,而在前面总结整理的react中,都是直接将路由配置放在需要使用的地方,少数的时候话可以接受,但是当项目做大,这种方式就不再被推荐了,我们再r ...
- css文字链接滑过向上移动1像素
方法一:行高 a{line-height:22px;} a:hover{line-height:21px;} 方法二:定位 a{position:absolute;top:0;} a:hover{ ...
- 还在用慢的要死的百度网盘?来试试这款12.5M下载速度的免费网盘吧!
我们都知道云存储,如谷歌云端硬盘,苹果的icloud, 微软的OneDrive. 它们是用于数据备份和与多设备同步的云存储. 虽然它被广泛使用,但是还是有一些缺点,以谷歌云端硬盘为例: 1. 如果你需 ...
- [UE4]制作按钮小技巧
Normal和Pressed一样的图片和大小,Hovered也是一样的图片但是大小比Normal稍微大一点,这样点击按钮的时候就会产生按钮被按下去的感觉.
- PhysX Clothing for UE4
转自:http://www.52vr.com/article-737-1.html Hello! 之前看到论坛里有人发了个关于UE4布料的小知识,于是跟帖说抽空写个布料的工作流程供大家参考,那么,今天 ...