1. 什麼是MVC架構 html
MVC是模型(model)-視圖(view)-控制器(controller)的縮寫。MVC是一個框架模式,它強制性的使應用程序的輸入、處理和輸出分開。其中, java
(1)模型用來模擬應用所管理的真實世界的事物。 mysql
(2)視圖是應用中展現給用戶看的那一部分,一般被稱爲表示層。 web
(3)控制器是應用的真正大腦。它決定了應用怎樣和系統交互、控制着那些數據能夠從模型中得到,以及視圖中的那一部分用來表示這些數據。 正則表達式
2. 什麼是對象-關係映射(ORM),Rails所採用的ORM層是什麼? sql
答:對象-關係映射(ORM)是一種爲了解決面向對象與關係數據庫存在的互不匹配的現象的技術,好比java系列的Hibernate就是一個輕量級ORM框架。 數據庫
Rails所採用的ORM層是一個名爲ActivityRecord的對象-關係映射庫。 編程
3. 如何建立一個rails應用程序demo。 json
答: api
(1) 使用RedRails工具建立一個rails程序demo的方法:
a) 單擊File -> New -> 選擇Rails Project
b) 輸入Project name後按下」Finish」鍵便可
(2) 在命令行下建立一個Rails應用
a) 建立D:\work目錄,在 DOS下進入此目錄,而後執行命令「rails demo」,就獲得一個Rails項目。
b) 在DOS下進入 D:\work\demo目錄,執行命令「ruby script/server」來啓動來啓動 WEB服務器。
4. 實現demo的第一個action,要求在瀏覽器窗口中輸入http://localhost:3000/test/first_action按回車後,頁面顯示「This is my first action.」
答:
(1)新建一個rails的程序,取名helloDemo。
(2)在目錄app/controllers/下新建一個rb文件,命名爲test_controller.rb。
打開test_controller.rb文件,輸入以下代碼:
(3) 在目錄app/views/ 下新建一個目錄爲test, 並在該目錄下新建一個first_action.html.erb的文件。
打開first_action.html.erb文件,輸入如下代碼並保存:
(4) 重啓server,而後運行該Rails程序,在瀏覽器中輸入http://localhost:3000/test/first_action,後顯示
5. ERB文件中如何插入ruby代碼?
答: ERb 模板,其實是Ruby 內建的、用於生成HTML的工具,一般用於生成HTML 頁面。最簡單的ERb 模板就是一個普通的HTML 文件。ERB文件中插入ruby代碼的方法有:
(1) 使用<% %>:不會返回運算結果。
(2) 使用<%= %>:<%= 和%> 之間的代碼會被求值,而後用to_s() 方法將結果轉換成字符串,最後將這個字符串顯示在結果頁面上。
6. ERB文件裏用ruby代碼實現一個循環。
答:程序代碼和運行結果以下
<html> <head> <title>Hello, Rails!</title> </head> <body> <% str="hello world\n\n" %> <% a=1 %> <% while a<4 %> <h2><%= str %></h2> <% a=a+1 %> <% end %> </body> </html> |
運行結果以下:
7. ERB的<%= %>序列末尾加上/去掉減號(把%>變成-%>),頁面顯示有什麼區別?
答:這裏的減號是在告訴ERb ,不要把緊隨其後的空格和空行放進HTML 輸出結果中。
8. 在demo添加代碼,讓第4題的頁面顯示當前時間,格式爲「2010-05-18 10:43:45」
答:程序代碼和運行結果以下
<html> <head> <title>Hello, Rails!</title> </head> <body> The time <% @time = Time.now.strftime("%Y-%m-%d %H:%M:%S") %> is <%= @time %> </body> </html> |
運行結果以下:
9. 在控制器test中新增一個action(second_action),實現它與first_action之間的互相跳轉。
答:
(1) 首先在目錄app/controller/test_controller.rb文件中新增一個second_action方法。
(2) 而後,在views/test/目錄中新增一個action命名爲」second_action.html.erb」。
打開文件,輸入代碼:
(3) 最後,重啓server,運行程序。
運行結果以下:
點擊連接跳轉至second_action
10. 調用下列方法會返回一個列表,其中包含當前目錄的全部文件:
Dir.glob(‘*’)
要求在頁面中用 <ul>顯示該文件列表。
答:新增一個action命名爲exer3_action,並輸入以下代碼
<html> <head> <title>第3周做業,題10</title> </head> <body> <%dirArr=Dir.glob('*') %> <ul> <%for element in dirArr %> <li> <%= element -%> </li> <%end %> </ul> </body> </html> |
運行結果以下:
《Web敏捷開發之道》(5-13)
=====================================================================
1. 建立rails應用程序depot,後臺使用mysql數據庫,建立數據庫depot_development,depot_production,depot_test,給出配置應用程序數據庫方法。
答:
(1) 在項目的目錄中使用」rails --database=mysql depot」命令建立一個使用mysql的應用程序,程序命名爲depot。
(2)打開項目的目錄」 安裝路徑\depot\config\」目錄下的’database.yum’配置文件,就發現項目自動配置的程序數據庫。
# MySQL. Versions 4.1 and 5.0 are recommended. # # Install the MySQL driver: # gem install mysql # On Mac OS X: # sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql # On Mac OS X Leopard: # sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config # This sets the ARCHFLAGS environment variable to your native architecture # On Windows: # gem install mysql # Choose the win32 build. # Install MySQL and put its /bin directory on your path. # # And be sure to use new-style password hashing: # http://dev.mysql.com/doc/refman/5.0/en/old-client.html development: adapter: mysql encoding: utf8 database: depot_development pool: 5 username: root password: icyi4cy host: localhost # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: mysql encoding: utf8 database: depot_test pool: 5 username: root password: icyi4cy host: localhost production: adapter: mysql encoding: utf8 database: depot_production pool: 5 username: root password: icyi4cy host: localhost |
2. 用遷移腳本建立數據庫表products,表有3列,分別爲(title(string,長度<=50),description(text),image_url(string)),給出遷移腳本代碼和建立方式
答:
(1) 使用Rails來建立數據庫的命令「depot> rake db:create RAILS_ENV='development'」
(2) 使用遷移腳本建立表products。
繼續輸入命令:「ruby script/generate scaffold product title:string description:text image_url:string 「
(3) 執行遷移任務的命令:」 depot> rake db:migrate」
3. 建立「貨品維護」應用,要求能夠實現貨品的增長、刪除、修改、查看功能答:
答:按照題目2的步驟進行後,
(1)本地主機啓動一個web服務器:」 depot> ruby script/server」
(2)打開一個瀏覽器,輸入URL」 http://localhost:3000/products」
(3)單擊連接「New product」按鈕,增長產品
(4)點擊「create」按鈕,新的貨品會成功建立,若是你點擊 Back 連接,你就會看到新的貨品出如今列表中。
(5)點擊商品後面的」Destroy」超連接,則跳轉以下:
4. 用遷移腳本給products表增長1列,爲(price(decimal,初始值爲0,只保存2位小數))
答:
(1) 使用遷移腳本給Products表增長1列,遷移腳本爲:「rails generate migration add_price_to_product price:decimal」。
(2)打開新生成的文件「db/migrate/20080514090912_add_title_body_to_post.rb「並以下修改。
class AddPriceToProduct < ActiveRecord::Migration def self.up add_column :products, :price, :decimal, :precision => 8,:scale => 2,:default => 0 end def self.down remove_colum :products, :price end end |
(3)再次運行數據遷移。
(4)修改相關view,增長與字段price相關的內容,在model目錄的product.rb文件裏添加屬性:price
(5)刷新頁面,便可看見新添加的自動
(6)點擊「New Product」超連接,能夠看到。
5. 增長對頁面輸入的驗證,title,description,image_url不能爲空,title的長度不能大於50,若是輸入出錯,在頁面反應出來
答:Ruby2提供的較驗方法的API位置:
其中大概許多校驗的輔助方法簡化操做有:
validates_acceptance_of 確認表單的checkbox是否被標記 validates_associated 確認關聯對象,每一個關聯對象的nil?法被調用 validates_confirmation_of 確認字段和指定字段的值是否有一樣的內容 validates_each 確認塊內的每一個屬性 validates_exclusion_of 確認指定的屬性值不會出如今一個特定的可枚舉對象中 validates_format_of 確認指定的屬性值是否匹配由正則表達式提供的正確格式 validates_inclusion_of 確認指定的屬性值是不是一個特定的可枚舉對象中的一個有效值 validates_length_of 肯定指定的屬性值是不是匹配約束的長度 validates_length_of爲其別名 validates_numericality_of 確認一個屬性值是不是數字 validates_presence_of 確認指定屬性值是否爲空 validates_uniqueness_of 肯定指定的屬性在系統中是否惟一 |
根據API文檔,檢驗一個字段的長度的方法以下:
此外,在Rail3版本中,還可使用validate(*attributes)方法
在這兒咱們使用第一個方法,打開models目錄下的product.rb文件,輸入以下信息:
class Product < ActiveRecord::Base attr_accessible :description, :image_url, :title, :price # 檢查指定字段存在、而且值不爲空 validates_presence_of :title, :description, :image_url # 數值合法性檢查 validates_numericality_of :price # 確保每樣貨品都有一個獨一無二的名稱(title) validates_uniqueness_of :title # 確保title的長度不大於50 validates_length_of :title, :maximum => 50 # 驗證輸入的圖片地址URL合法性 validates_format_of :image_url, :with => %r{\.(gif|jpg|png)$}i, :message => 'must be a URL for GIF, JPG or PNG image.(gif|jpg|png)' end |
從新刷新頁面,輸入長度大於50的Title,頁面顯示結果以下:
6. 經過使用佈局實現《Web敏捷開發之道》P93的圖7.3頁面,在點擊圖書封面圖片時,也調用add_to_cart這個action。
提示:用link_to和image_tag,這兩個標籤的具體使用方法請查閱http://api.rubyonrails.org
答: 咱們能夠將depot \app\views\store\ index.html.erb文件下的這條語句
<%= image_tag(product.image_url) %>
替換成以下語句:
<%=link_to image_tag(product.image_url),:action=>:add_to_cart,:id => product,:method => post %> |
可是因爲並無add_to_cart這個action存在,所以咱們就用如下語句替換:
<%=link_to image_tag(product.image_url), line_items_path(product_id: product) %> |
7. 在以上建立的應用中使用session存儲某頁面被訪問的次數,並在頁面上顯示出來。
答:
在depot\app\controllers\store_ controller文件中增長以下代碼:
class StoreController < ApplicationController def index @products = Product.order(:title) if session[:count].nil? session[:count]=1 else session[:count] +=1 end end end |
而後再depot\app\views\store\index.html.erb文件中增長以下語句:
<h1>browse counts: <%= session[:count]%> -Your Pragmatic Catalog </h1> |
刷新頁面,便可發現訪問次數在不斷增長,
8. Rails應用中flash的做用是什麼?flash裏的內容在何時有效?如何在頁面中顯示flash裏的內容?
答:Rails應用中的flash的結構和Hash很相似,咱們能夠在處理請求的過程當中把任何東西放進去,也就是說,flash通常都是用於收集錯誤信息的。
flash的生命週期爲一個session,即在同一個session的下一個請求中,你可使用flash的內容,而後這些內容就會被自動刪除。
使用flash方法能夠訪問flash中的內容,例如:
flash[:notice] = 「Invalid product」 |
9. 參照第9章內容,當用戶點擊「Add to Cart」按鈕時,只更新局部頁面,如插入一段html代碼到頁面的某個div中
答:
想要達到Ajax的效果,即點擊「Add to Cart」連接,看到只有div購物車信息被更新,同時瀏覽器卻不會有任何刷新頁面的跡象。
原先咱們是使用button_to()來建立咱們的「Add to Cart」連接的,其實,button_to()方法就是生成了HTML的<form>標記。原先咱們的調用方法
<%= button_to 'Add to Cart', line_items_path(product_id: product) %> |
會生成這樣的相似HTML代碼
<form method="post" action="/store/carts/1"class="button-to"> <input type="submit" value="Add to Cart" /> </form> |
咱們首先在改代碼後添加一段「, remote: true」,以下
<% if notice %> <p id="notice"><%= notice %></p> <% end %> <h1>Your Pragmatic Catalog</h1> <% @products.each do |product| %> <div class="entry"> <%= image_tag(product.image_url) %> <h3><%= product.title %></h3> <p><%= sanitize(product.description) %></p> <div class="price_line"> <span class="price"><%= number_to_currency(product.price) %></span> <%= button_to 'Add to Cart', line_items_path(product_id: product), remote: true %> </div> </div> <% end %> |
首先是,咱們要當咱們要請求javascrip時中止creat這個action向index頁面重定向。這樣咱們要給respond_to()方法增長一個請求,告訴它咱們想要一個.js文件的應答。所以,修改app/controllers/line_items_controller.rb文件的creat方法:
def create @cart = current_cart product = Product.find(params[:product_id]) @line_item = @cart.line_items.build @line_item.product = product @line_item = @cart.add_product(product.id) respond_to do |format| if @line_item.save format.html { redirect_to @line_item.cart, notice: 'Line item was successfully created.' } format.js format.json { render json: @line_item, status: :created, location: @line_item } else format.html { render action: "new" } format.json { render json: @line_item.errors, status: :unprocessable_entity } end end end |
而後,咱們在depot_l/app/views/line_items/目錄下新建一個「create.js.erb」文件,輸入以下代碼:
$('#cart').html("<%=j render @cart %>"); |
先清空購物車Cart,從新載入頁面,彈出以下頁面:
而後咱們再次刷新頁面,點擊「Add to cart」按鈕,此時只有左邊的購物車的區域發生變化,增長了一個lineItem,而沒有重定向到index.html頁面,圖片以下:
這樣就成功實現了Ajax效果。
10. 模型的單元測試和控制器的功能測試如何進行,徵對應用中的某個model和某個controller,各舉一個例子
答:
(1) 模型Product的單元測試
在前面咱們定義Product的model的時候,定義了以下方法,用來檢驗數據:
class Product < ActiveRecord::Base attr_accessible :description, :image_url, :title, :price validates_presence_of :title, :description, :image_url validates_numericality_of :price validates_uniqueness_of :title validates_length_of :title, :maximum => 50 validates_format_of :image_url, :with => %r{\.(gif|jpg|png)$}i, :message => 'must be a URL for GIF, JPG or PNG image.(gif|jpg|png)' end |
知道這些校驗邏輯確實起做用了就得靠測試,在咱們用腳手架生成Product的時候,Rails已經自動爲咱們生成了一套test框架. 首先,若是建立一個貨品卻不給它設置任何屬性,咱們但願它不能經過校驗,而且每一個字段都應該有對應的錯誤信息。
(a)於是咱們打開depot\test\unit目錄下的product_test.rb文件並編輯:
require 'test_helper' class ProductTest < ActiveSupport::TestCase # test "the truth" do # assert true # end test "product attributes must not be empty" do product = Product.new assert product.invalid? assert product.errors[:title].any? assert product.errors[:description].any? assert product.errors[:price].any? assert product.errors[:image_url].any? end end |
(b)輸入rake test:units命名
(2) 控制器Controller的功能測試。
控制器負責控制用戶界面的展現。它們接收進入的web請求(一般是用戶的輸入),與模型對象進行交互以得到應用程序的狀態,而後找到合適的視圖顯示給用戶。因此,當對控制器進行測試時,咱們必須確保必定的請求可以獲得合適的應答.
在這兒,咱們的Product模型已經測試過了,於是只須要對controller進行測試。打開文件/test/functional/store_controller_test.rb。增長四段代碼:
require 'test_helper' class StoreControllerTest < ActionController::TestCase test "should get index" do get :index assert_response :success assert_select '#columns #side a', minimum: 4 assert_select '#main .entry', 3 assert_select 'h3', 'Programming Ruby 1.9' assert_select '.price', /\$[,\d]+\.\d\d/ end end |
輸入rake test:functionals命令:
《Web敏捷開發之道》(14-19)
=====================================================================
1. 如何將Rails自己固化到程序裏?
答:爲了確保程序始終能夠獲得正確的Rails版本。一種方法是直接將Rails代碼固化(freeze)在應用程序的目錄中,這樣一來,Rails庫就和應用程序代碼一道保存在版本控制系統中了。
其方法以下,只要輸入下列命令便可:
depot>rake rails:freeze:gems
這個命令會在幕後將最新版本的Rails庫拷貝到vendor/rails目錄下——當應用程序啓動時,Rails會首先到這裏來尋找本身須要的庫,而後再尋找全系統共享的版本。若是在固化以後但願取消綁定、繼續使用系統共享的Rails版本,能夠直接把vendor/rails目錄刪掉,也能夠執行下列命令:
depot>rake rails:unfreeze
2. 當運行應用程式時,怎樣指定運行時環境?
答:編寫代碼、測試和工做環境下的運行,在這三個階段,開發者的須要有很大差別。
◆在編碼階段,你但願看到更多的日誌、可以當即加載修改過的代碼、直觀的錯誤提示,等等。
◆在測試階段,你就須要一個與世隔絕的環境,這樣測試才具備可重複性。
◆在真實運行時,系統須要最優化的效率,而且不該該讓用戶看到錯誤。
爲了支持這些不一樣的需求,Rails引入了運行時環境的概念。每一個運行時環境都有本身的一組配置參數。當運行應用程序時,你就能夠指定運行時環境。譬如說,若是你使用rails server來運行,能夠加上-e選項:
depot> rails server -e development # the default if -e omitted
depot> rails server -e test
depot> rails server -e production
3. rails中求一個字符串所包含的字符數的函數是什麼?如求的字符長度
答:Multibyte庫並無將Ruby內建的字符串類庫替換成可以處理Unicode的版本,而是義了一個名叫Chars的新類型。這個類定義了與內建的String類相同的方法,惟一區別是這些方法都可以處理多種字符編碼方式。
使用多字節字符串的規則很是簡單:但凡須要處理UTF-8編碼的字符串時,都應該首先將這些字符串轉換成Chars對象。Multibyte庫給String類加上了chars方法,讓這個轉換變得易如反掌。 方法以下:
E:\RubyOnRailProj\depot>rails console
Loading development environment (Rails 3.2.11)
irb(main):001:0> name = "G\303\274nter"
=> "Günter"
irb(main):002:0> name.mb_chars.length
=> 6
4. 如何使用遷移任務修改字段名、字段類型、給表添加索引?
答:(1) 咱們能夠經過在用遷移任務時使用rename_column()方法來修改字段名,好比將原來的e_name更名爲customer_email,代碼以下:
class RenameEmailColumn < ActiveRecord::Migration def change rename_column :orders, :e_mail, :customer_email end end |
此時,由於更名操做是可逆的,所以可使用change()方法,而不須要使用up()和down()方法。
(2) 咱們能夠經過在用遷移任務時change_column()方法來修改字段類型。此時注意最好使用self.up()和self.down()方法,由於可能類型之間的轉換不是可逆轉的。而且,要注意類型轉換異常。例如,咱們將原來爲integer類型的order字段改變成String類型,代碼以下:
class ChangeOrderTypeToString < ActiveRecord::Migration def self.up change_column :orders, :order_type, :string, :null => false end def self.down raise ActiveRecord::IrreversibleMigration end end |
(3) 咱們能夠經過在用遷移任務時用add_index()方法給表添加索引。例如,當數據庫中有不少訂單數據時,根據顧客名字搜索訂單數據就會變得很慢。此時,就應該給這張表加上索引了,方法以下:
class AddCustomerNameIndexToOrders < ActiveRecord::Migration def change add_index :orders, :name end end |
5. 如何經過model向數據庫中添加一條記錄。
答: 咱們可使用面向對象的方法經過model向數據庫中添加一條記錄。好比,咱們只要調用Order.new()方法,就能夠建立一個Order對象,它表明着orders表中的一條記錄;隨後咱們能夠填充該對象各個屬性(對應於數據庫中的字段)的值;最後調用該對象的save()方法,就能夠將它存入數據庫。代碼以下:
an_order = Order.new an_order.name = "Dave Thomas" an_order.email = "dave@example.com" an_order.address = "123 Main St" an_order.pay_type = "check" an_order.save |
或者使用如下方法:
an_order = Order.new( name: "Dave Thomas", email: "dave@example.com", address: "123 Main St", pay_type: "check") an_order.save |
6.用Order.find方法實現下列sql語句」select * from orders where id=2 and name like ‘a%’ order by id DESC」
答:代碼以下,
orders=Order.find(:all, :conditions => ["id = '2'" and "name like ?",'a'+"%"], :order => "id DESC") |
7. 用ActiveRecord的方法實現order(id:integer, amount:integer)表裏面id大於3小於100的全部記錄的amoun字段的值的和。
答:代碼以下,
total= Order.sum :id, :conditions => "id > 3 and id <100" |
8. 使用ActiveRecord定義外鍵的命名約定是什麼?
答: ActiveRecord的命名約定:外鍵字段的名字應該以被引用的目標表名爲基礎,將其轉換爲單數形式,並加上_id後綴。外鍵字段使用了單數形式與_id後綴,也就是說它的名字必定與目標表名不一樣。
好比,在下圖表示,數據庫中一個訂單(orders)有零個或多個訂單項(line_items),它們分別映射的ActiveRecord模型類爲Order和LineItem,其中在line_items表中引用orders表所使用的外鍵字段名就應該是order_id。
9. Rails中如何實現表間的一對1、一對多、多對多的關聯
答:ActiveRecord 支持三種表間關聯:一對一(one-to-one)、一對多(one-to-many)、多對多(many-to-many)。你須要在模型類中加上聲明以便指明使用哪一種關聯:has_one、has_many、belongs_to或has_and_belongs_to_many。
(1) 一對一的關聯:實現方式是在其中任意一張表裏保存外鍵字段,引用另外一張表裏的記錄。以下圖,在Invoices表中有一個orders表的外鍵,此時須要在有外鍵的Invoice模型類中使用belongs_to :order的聲明,同時在被引用的Order模型類中使用has_one :invoice的聲明。
(2) 一對多的關聯:父對象(它在邏輯上包含一組子對象)應該使用has_many來聲明與子對象的關聯,子對象則應該用belongs_to來聲明與父對象的關聯。以下圖,因爲line_items表包含外鍵,因此,LineItem對象就應該包含belongs_to聲明,而在一對多的關係中「一」的那方(好比這兒一個訂單對多個訂單項,這兒訂單就是關係中「一」的那方)中使用has_many聲明
(3) 多對多的關聯:多對多關聯是對稱的——兩個模型類都用has_and_belongs_to_many來聲明本身與對方的關係。
10. 如何實現僅在建立記錄時校驗某個數據庫字段ip_address的值是不是ip地址?
答:根據查看Rails的API得,
在該方法的可選項上有一個’:on’參數,能夠指定指定校驗進行的時機,可選的值有:save(默認值)、:create和:update,在本題中咱們使用」:create」
而判斷一個IP地址的正則表達式以下:
於是,該題代碼以下:
class Demo < ActiveRecord::Base validates_format_of :ip_address, :on => :create, :with => %r{((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3} (2[0-4]\d|25[0-5]|[01]?\d\d?)$}i end |
《Web敏捷開發之道》(20-25)
=====================================================================
1. 將外部URL跟內部應用程序對應起來的文件是什麼?
答:config/routes.rb文件創建了一個映射關係,將外部的URL與內部的應用程序鏈接起來。
2. 對於controller爲a, action爲b的方法,爲其定義路由,映射url爲’a/cdef’,post請求
答:根據路由定義規則,代碼以下。
ActionController::Routing::Routes.draw do |map| map.connect 'a/cdef' , :conditions => { :method => :post }, :controller => "a" , :action => "b" end |
3. 應用程序routes.rb文件中map.reource :books, :collection=>{:latest=>:get}和map.resource :book, :member=>{:hide=>:put,:relase=>:put},它們添加的路由規則是什麼?有什麼區別?
答:map.reource :books, :collection=>{:latest=>:get}的路由規則爲新增一個名叫latest的action,並用HTTP GET方法來訪問它,它適用於books資源。
map.resource :book, :member=>{:hide=>:put,:relase=>:put}的路由規則爲:爲資源book單獨創建一個action,將book標記爲「隱藏」或「發佈」。
4. 使用render(:action => :index)會不會調用index方法,爲何?
答: 不會調用index方法,只會渲染index的默認模板。
由於,render(:action =>action_name)方法用於渲染當前控制器中指定的action所對應的模板。調用render(:action =>action_name)並不會調用後一個action方法,只是把模板渲染出來。
5. 編寫程序,要求:頁面上有一個上傳按鈕和一個下載按鈕,實現文件上傳和下載。
答: 在HTTP 協議中,文件是做爲一種特殊的POST 消息上傳到服務器的,其消息類型是multipart/form-data,便是由表單生成的。你能夠在表單內部放置一個或多個帶有type="file"屬性的<input>標籤,在瀏覽器上顯示時,該標籤會容許用戶選擇一個文件;當這樣的表單被提交到服務器時,文件內容就會與其餘表單數據一道被送回服務器。
一個基本的上傳按鈕的代碼以下,
<%=start_form_tag ({:action=>"upload"},:multipart=>true )%> <input id="upload" name="upload" type="file" /> <%=end_form_tag%> |
其中<input type="file" />的標籤即是提供上傳的標籤,設置的「:multipart=>true」,編譯後的代碼即是「enctype=」multipart/form-data」」。該段代碼的顯示結果以下,
咱們也可使用rails提供的form_for和form_tag方法來生成模板,其中根據ROR的guildes(網站http://guides.rubyonrails.org/form_helpers.html#uploading-files)可得
以上傳一個圖片爲例子。
(1)首先,建立一個表來保存上傳的數據,使用scaffold,假設咱們是要在Product表上的img字段上,上傳圖片數據。
rails generate scaffold Product title:string img:string |
這樣在db/migrate文件中就能夠找到XXX_create_products.rb文件,打開文件獲得,
class CreateProducts < ActiveRecord::Migration def change create_table :products do |t| t.string :title t.string :img t.timestamps end end end |
(2)在控制器ProductsController文件中,建立一個名爲uploadImg的控制器,並添加以下代碼。
def uploadImg end |
(3)在app/view/products文件中添加一個名爲uploadImg.html.erb的文件,添加的代碼以下,
<% if notice %> <p id="notice"><%=notice %></p> <% end%> <h1>Upload </h1> <%= form_tag "/products/upload",:multipart => true do%> <%= file_field_tag(:img,:size=>"40")%> <%= submit_tag("上傳文件")%> <% end%> |
(4)在控制器ProductsController文件中再添加upload方法,代碼以下。
def upload image=params[:img] content_size=image.size file_data=image.read filetype=image.content_type @filename=image.original_filename File.open("#{Rails.root}/public/"+@filename,"wb"){|f| f.write(file_data)} flash[:notice]="file:"+@filename+"upload success" render :action=>"uploadImg" end |
其中的「image=params[:img]」是得到上傳的文件對象。另外,代碼「file_data=image.read」一旦獲取上傳文件二進制數據,就能夠經過IO流將這些數據寫入到服務器的文件中。
(5)最後再修改config文件下的routes文件中的代碼,以下。
UploadDemo::Application.routes.draw do match 'products/uploadImg' => 'products#uploadImg' match 'products/upload' => 'products#upload' root :to=>"products#uploadImg" resources :products end |
(6)運行程序,在地址欄輸入http://localhost:3000/products/uploadImg,單擊「瀏覽」上傳圖片時顯示以下,
單擊「上傳文件」後,頁面顯示以下,
同時,查看項目根目錄下的public文件,發現長傳成功的hello.jpg文件
文件的下載。
文件的下載有send_file和send_data兩種方法,在本題中使用send_data的方法。send_data的API以下,
send_data(data, options = {}) Sends the given binary data to the browser. This method is similar to Options: · · · · |
注意選項」 :disposition
」的值有」 inline」和」 attachment」,分別表示是直接顯示方法下載仍是使用附件的形式下載。
(1)修改app/view/products目錄下的index.html.erb文件,增長一個button按鈕。修改的代碼以下,
<h1>Listing products</h1> <table> <tr> <th>Title</th> <th>Img</th> <th></th> <th></th> <th></th> </tr> <% @products.each do |product| %> <tr> <td><%= product.title %></td> <td><%= product.img %></td> <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> <td><%= button_to 'download', :action=>"downSendData",:filename=>"#{product.img}.jpg" %></td> </tr> <% end %> </table> <br /> <%= link_to 'New Product', new_product_path %> |
(2)在控制器文件中添加downSendData方法,代碼以下,
def downSendData io=File.open("#{Rails.root}/public/"+params[:filename]) io.binmode send_data(io.read,:filename=>params[:filename],:type=>"image.jpg" ,:disposition=>"attachment") io.close end |
(3)在config目錄下的routes文件中添加以下的代碼。
UploadDemo::Application.routes.draw do match 'products/uploadImg' => 'products#uploadImg' match 'products/upload' => 'products#upload' match 'products/downSendData' => 'products#downSendData' root :to=>"products#uploadImg" resources :products end |
(4) 運行程序,在地址欄輸入http://localhost:3000/products/獲得,以下畫面,而後點擊」download」按鈕,即顯示下載該文件的對話框。
6.信息存儲到session應該注意什麼?
答: 將信息存儲到session應該注意,
(1) 可以放入session的對象是有限制的,通常而言,session中的對象必須是可序列化的。
(2) 不要把擁有大量數據的對象放進session。能夠把它們放進數據庫,而後在session中引用這些數據。
(3) 不要把常常變化的對象放進session。常常變化的數據應該放進數據庫,而後從session中引用這些數據
(4) 不要把關鍵信息單獨放進session關鍵信息應該保存在數據庫中,而後從session中引用這些數據。
7. 如何實現將session數據保存到應用程序所使用的數據庫中。
答:ActionController::Base中的session_store屬性值,能夠指定session的存儲機制。
將session數據保存到應用程序所使用的數據庫中,可設置屬性
session_store = :active_record_store。 |
而後使用rake 任務建立sessions表。
depot> rake db:sessions:create |
再運行rake db:migrate就能夠實際建立這張表。
8. 編碼實現採用ActiveRecord存儲的過時session數據(最近2天沒有更新的)
答: 採用ActiveRecord存儲session數據,利用sessions數據庫表中的updated_at字段,而後執行SQL就能夠刪除全部在大於2天中沒有更新的session數據,剩下存儲的就是最近兩天沒有更新的sessoin數據,SQL代碼以下,
delete from sessions where now() - updated_at > 3600*24*2; |
9. 使用前置過濾器實現以下內容:定義一個authorize方法用於身份驗證,若是當前session中沒有登陸用戶信息,就重定向到登陸界面。
答:前置過濾器會在action以前被調用,後置過濾器則在action以後調用。Rails會針對這兩種過濾器分別維護一個鏈表。在執行action以前,控制器會首先執行前置鏈表中的全部過濾器;在action執行完畢以後再執行後置鏈表中的全部過濾器。在本題中,程序代碼以下,
class ApplicationController < ActionController::Base before_filter :authorize protected def authorize unless User.find_by_id(session[:user_id]) redirect_to login_url, notice: "Please log in" end end end |
10. 編程實現帶選項分組的列表選擇
答: 在選擇列表中分組,這項功能並不經常使用,但卻很是強大:你能夠用這種方式來給列表中的選項加上標題。
完整的列表能夠看做是一個包含多個分組的數組,每一個分組又是一個對象,由「分組名稱」與「子選項集合」兩部分組成。在本次編程中,咱們準備了包含「發貨選項」的一個列表,並按照「交付速度」將其分組。
第一步:在輔助模塊中,咱們定義了一個與數據庫無關的模型類Shipping來表明「發貨選項」,並用一個類來表明「一組發貨選項」。而後,咱們在代碼中初始化了三個分組。
class Shipping ShippingOption = Struct.new(:id, :name)
class ShippingType attr_reader :type_name, :options def initialize(name) @type_name = name @options = [] end def <<(option) @options << option end end ground = ShippingType.new("SLOW" ) ground << ShippingOption.new(100, "Ground Parcel" ) ground << ShippingOption.new(101, "Media Mail" ) regular = ShippingType.new("MEDIUM" ) regular << ShippingOption.new(200, "Airmail" ) regular << ShippingOption.new(201, "Certified Mail" ) priority = ShippingType.new("FAST" ) priority << ShippingOption.new(300, "Priority" ) priority << ShippingOption.new(301, "Express" ) OPTIONS = [ ground, regular, priority ] end |
第二步:在視圖中建立一個選擇列表控件,以便顯示輔助模塊提供的列表。這裏沒有一個高級的包裝方 法 可 以 方 便 地 創 建<select>標 籤 並 用 分 好 組 的 標 籤 填 充 , 所 以 我 們 只 得 改 用option_groups_from_collection_for_select()方法。該方法的參數包括一個分組的集合、用於獲取分組信息與選項信息的訪問方法名,以及模型對象的當前值。咱們把這些放在一個<select>標籤的內部,該標籤的名字是模型對象名和屬性名的組合。
<label for="order_shipping_option" >Shipping: </label> <select name="order[shipping_option]" id="order_shipping_option" > <%= option_groups_from_collection_for_select(Shipping::OPTIONS, :options, :type_name, # <- groups :id,:name, # <- items @order.shipping_option) %> </select> |