We will first build the Categories page. This page contains topics like Art, Home & Living, and Kids, so our users can browse through categories and find what they like.
Each Category in our site will need to store information about itself, such as a name and an image. Our Category Model is what stores information about our Categories. Remember that our Model manages the data in our app.
===============================
1. Build Model
2. Build Migration Table
3. Add Data to Tables
4. Generate Table Controller
5.
===============================
开始之前,我们要先建立Model用来存储每个Category的数据模型。
We can generate a Model with the following rails command:
rails generate model Person
Here Person
is an example name for our Model. Model names are always singular.
Category
using the rails command. Press Enter.
rails generate model Category
In terminal:
$ rails generate model Category invoke active_record create db/migrate/20141013165110_create_categories.rb create app/models/category.rb invoke test_unit create test/models/category_test.rb create test/fixtures/categories.yml $
Our Model is fine for now. Let's prepare our Migration table. We do this in two steps:
a. We add columns to our Category Migration table. These will define what information our database can accept.
b. We type bundle exec bundle exec rake db:migrate in our terminal to migrate our database, or update its state.
Let's look at an example. Say we had a Person Model, and we want it to have the columns name and age. In the Migration table, we add columns like this:
def change
create_table :person do |t|
t.string :name
t.integer :age
t.timestamps
end
end
Above we add t.string :name
andt.integer :age
specifying the name of type string and the age of type integer. We run db:migrate to add a name and age column to our actual database.
Add a name
and thumburl
attributes to your category migrations. These are both strings. Hit Run.
In your terminal, runbundle exec rake db:migrate
to migrate your database. Press Enter.
class CreateCategories < ActiveRecord::Migration def change create_table :categories do |t| t.string :name t.string :thumburl #t.timestamps end end end
Terminal:
$ bundle exec rake db:migrate == 20140626211003 CreateCategories: migrating ================================= -- create_table(:categories) -> 0.0010s == 20140626211003 CreateCategories: migrated (0.0010s) ======================== $
Now that we have columns, we need to add data. This file(in the seeds.rb file) on the below might look intimidating, but it is a simple list of data for our Rails app.
# 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') # Add your category here
How does this work? We store data in two steps.
a. We first add seed data in the seeds.rb file
b. We run rake db:seed in our terminal.
已经加了数据在例子里,这里再练习一下seeding data : Let's look at a small example first.
gia = Person.create(name: 'Gia', age: '8')
Here we create a new object in the Person class with the name Gia and age8. We store this object in a variablegia.
Now let's look at some seed data for Category.
weddings = Category.create(name: 'Weddings', thumburl: 'http://hostingessence.com/wp-content/uploads/2012/04/green-wedding.jpg')
Here, we create a new object in the Category class with the name of Weddings and athumburl. We store this in the variable weddings.
=========== Instructions ===========
Look in your seeds file, seeds.rb. On line 17, add seed data for craft_supplies
. The entry should have a name'Craft Supplies'
and a thumburl of'http://bit.ly/1w1uPow'
. Store this entry in a variable called craft_supplies. Hit Run.
In your terminal, run rake db:seed
[更正:bundle exec rake db:seed ] to add the data from seeds into your database. Press Enter.
# Add your category here: craft_supplies = Category.create(name:'Craft Supplies',thumburl:'http://bit.ly/1w1uPow')in Terminal, type this command and hit Enter:
$ rake db:seed rake aborted! Gem::LoadError: You have already activated rake 10.4.2, but your Gemfile requires rake 10.3.2. Prepending `bundle exec` to your command may solve this. /var/lib/gems/2.0.0/gems/bundler-1.7.3/lib/bundler/runtime.rb:34:in `block in setup' /var/lib/gems/2.0.0/gems/bundler-1.7.3/lib/bundler/runtime.rb:19:in `setup' /var/lib/gems/2.0.0/gems/bundler-1.7.3/lib/bundler.rb:121:in `setup' /var/lib/gems/2.0.0/gems/bundler-1.7.3/lib/bundler/setup.rb:17:in `<top (required)>' /home/ccuser/workspace/ecommerce-rails-app/config/boot.rb:4:in `<top (required)>' /home/ccuser/workspace/ecommerce-rails-app/config/application.rb:1:in `<top (required)>' /home/ccuser/workspace/ecommerce-rails-app/Rakefile:4:in `<top (required)>' (See full trace by running task with --trace) $我们得到一个错误:rake aborted! 看它的说明,使用这个命令即可:
$ bundle exec rake db:seed
但目前我们table里的数据是static的,所以我们又要建立Controller,让我们来改变页面里的内容。In Rails,数据库操作的五个主要的方式methods: index, show, new, edit, delete. 这几个在动态Rails App里是一样的,对以后的学习有帮助。
还记得我们建立Persons Controller时候用的命令吗?
>> rails genertate controller Persons
所以我们就可以在命令行里添加methods,同时,Rails会updates相关的routes和Views for us.
例如,如果我们想要添加 index ,new, edit 这三个mothods到Persons这个Controller,使用如下的命令:
>> rails generate controller Persons index new edit
注:一般Controller的名字是plural复数,Model的名字是单数。
【好,这里的操作】1.In your terminal, generate a controller Categories with the main methods we’ll use: index, show, new, edit, and delete. Press Enter.
>> rails generate controller Categories index show new edit delete
$ rails generate controller Categories index show new edit delete create app/controllers/categories_controller.rb route get 'categories/delete' route get 'categories/edit' route get 'categories/new' route get 'categories/show' route get 'categories/index' invoke erb create app/views/categories create app/views/categories/index.html.erb create app/views/categories/show.html.erb create app/views/categories/new.html.erb create app/views/categories/edit.html.erb create app/views/categories/delete.html.erb invoke test_unit create test/controllers/categories_controller_test.rb invoke helper create app/helpers/categories_helper.rb invoke test_unit create test/helpers/categories_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/categories.js.coffee invoke scss create app/assets/stylesheets/categories.css.scss $
class CategoriesController < ApplicationController def index end def show end def new end def edit end def delete end end然后我们就要来写这些methods里的具体的语句。
但是,开始之前,我们要保证从model来的数据的安全,所以:
There's one step we do before writing our main Controller methods: we need our Controller to have a secure way of getting information from our Model.
We'll use a private method to do this called strong parameters. This method prevents a user from hacking into our app and changing our Model.
要让method ”strong parameters“ 变得private从而阻止黑客入侵。首先前面有个private, 然后加上这个strong params method, 这个会store all our infor 并且只让开发者访问下面的method.e.g.:
private def person_params params.require(:person).permit(:name, :age) end这里我们是以persons Controller为例,we make a private person_params method. In the body of the method, we require the Model name (person), and permit the columns (name, age).现在任何时候我们想要person的信息,我们都引用为我们存储了信息的person_params method.
【好,这里的操作】In categories_controller.rb, beneath the end
afterdef delete
, declare aprivate
method. Under the private, create acategory_params
method for categories. Remember to requirecategory
and permit aname
and thumburl
. Useend
to close it. Hit Run.
class CategoriesController < ApplicationController def index end def show end def new end def edit end def delete end #declare a private method private def category_params params.require(:category).permit(:name, :thumburl) end end上面用到了params.require,是一个验证method, 大意是只有name 和 thumburl可以被验证通过,存入model,详见:http://stackoverflow.com/questions/18424671/what-is-params-requireperson-permitname-age-doing-in-rails-4
**First, the index method. The index method takes every entry in our database and stores it as a variable.
If each record in our app is about person, the index method would show us all persons in our database. Just like a real index. It looks like this:
def index
@persons = Person.all
end
Here we take all persons, and store them in an instance variable @persons.
【操作】
在categories_controller.rb文件中:
def index @categories = Category.all end开始丰富下一个method之前,我们先来试一下index工作没有。
Rails.application.routes.draw do get '/' => 'pages#home' #这样写总算是让人有点明白了 resources :categories #这是一种方法,还有以下两种方法: #get '/categories' => 'categories#index' #get 'categories/index' #browser_url: http://localhost:8000/categories/index get 'categories/:id/delete' => 'categories#delete', :as => :categories_delete end
<h1>Categories#index</h1> <p>Find me in app/views/categories/index.html.erb</p>
Rails建立了一个route and View for us, 但是是个空的文件,改变index.html.erb文件,让它看起来好点。index视图应该怎么样的?index method保存了数据库的所有条目,所以index 视图应该显示出所有条目。看个例子:
Say we have a persons index page want to show all persons in our collection.
We write:
--------------
<% @persons.each do |person| %>
<tr>
<td><%= person.name %></td>
<td><%= person.age %></td>
</tr>
<% end %>
--------------
Here we go through each person stored in @persons with an iterator and print out the attributes person.name and person.age.
然后把这个应用在index.html.erb的cagegory组里:
**index.html.erb文件:
<h1>Listing categories</h1> <table> <thead> <tr> <th>Name</th> <th>Thumburl</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @categories.each do |category| %> <tr> <td><%= category.name %></td> <td><%= category.thumburl %></td> <td><%= link_to 'Show', category_path(category) %></td> <td><%= link_to 'Edit', edit_category_path(category) %></td> <td><%= link_to 'Destroy', category, method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> </tbody> </table> <br> <%= link_to 'New Category', new_category_path %>
此时再来访问localhost:8000/categories即可获得列表:
The index page we made has all the right information, but it didn't have the structure and style. We've added the supporting HTML code for the view.
文件和信息流程图如下,
但有几个疑问:
1. config/routes.rb文件中get 'categories/:id/delete' => 'categories#delete', :as => :categories_delete不能动,为啥?
2. routes.rb 与 Controller是怎么联系的?或者routes.rb, controller, view 三者是怎么联系?
3. index.html.erb文件中,
以下是加入了style效果的html:
<%= render 'shared/topnav' %> <div class="categories"> <div class="container"> <div class="row"> <div class="col-md-2"> <h2>Categories</h2> <p>Explore our latest categories from around the world.</p> </div> <div class="col-md-8"> <% @categories.in_groups_of(3).each do |categories| %> <% categories.select! {|x| !x.nil?} %> <div class='row'> <% categories.each do |category| %> <div class='col-md-4'> <div class="thumbnail"> <img src= <%= category.thumburl %> > <div class="caption"> <span class="listing-title"><%= category.name %></span> <span><%= link_to "Edit", edit_category_path(category.id) %></span> <span><%= link_to 'Show', category %></span> <td><%= link_to 'Delete', categories_delete_path(:id => category.id) %></td> </div> </div> </div> <% end %> </div> <% end %> </div> </div> </div> </div> <table> <thead> <tr> <th>Category name</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @categories.each do |category| %> <tr> <td><%= category.name %></td> <div class="thumbnail"> <img src= <%=category.thumburl %> > <div> <td><%= link_to 'Show', category %></td> <td><%= link_to 'Edit', edit_category_path(category) %></td> <td><%= link_to 'Delete', categories_delete_path(:id => category.id) %></td> </tr> <% end %> </tbody> </table> <br> <%= link_to 'New Category', new_category_path %> <%= render 'shared/footer' %>
** app/controllers/categories_controller.rb文件:
class CategoriesController < ApplicationController def index @categories = Category.all end def show end def new end def edit end def delete end private def category_params params.require(:category).permit(:name, :thumburl) end end
继续丰富我们的controller:
While index gave all categories, show allows us to access one category. This this is helpful when we want to show just one Category at a time in our Etsy app.
The show method works like this. we write:
def show @category = Category.find(params[:id]) end