2013-02-20 61 views
2

1.)是否可以創建一個不直接與模型交互的控制器動作? (即上傳要解析的文件,然後添加到數據庫模型)Rails的控制器如何工作?

2.)什麼是控制器的操作順序?我不明白控制器動作如何實例化視圖,並對用戶輸入的params變量作出反應。

有人請解釋一下,謝謝。

第二部分 - 路由模型體的票據

所以對於我目前的上傳表單,我有2個動作,上載操作(需要從用戶的文件),我想排到parse_upload行動(操縱在upload.html.erb視圖上傳的文件):

的routes.rb:

::Application.routes.draw do 
    devise_for :users 
    resources :revenue_models do 
     get 'upload', :on => :collection 
     put 'parse_upload',:on => :collection 
    end 
    root :to => "home#index" 
end 

操作:

# UPLOAD multiple files from an Exel Doc; integrate them accordingly 
def upload 
    @uploaded_doc = { :workbook => RubyXL::Parser.new }  
end 
# Parse the uploaded file 
def parse_upload 
@worksheet = RubyXL::Parser.parse(params[:uploaded_doc]  
        [:workbook]).worksheets[0].extract_data 
end 

upload.html.erb(我想這個上傳表單,以推動其PARAMS到parse_upload動作)

<%= form_tag(:url => {:controller => "revenue_models", :action => "parse_upload"}, :html => {:method => "put", :multipart => true}) do %> 
    <%= file_field(:uploaded_doc, :workbook) %> 
<%= submit_tag("Upload") %>  
<% end %> 

目前我得到一個路由錯誤,當我提交的文件: 沒有路由匹配[POST]「/revenue_models/upload「

我假設一切工作正常,直到從上傳表單到[parse_upload]操作的路由點。我嘗試了下面的更多答案,但由於在我的情況下,我沒有使用以現有模型爲中心的表單,所以我有點失落。任何線索是什麼問題?提前致謝。

回答

2

1 )是的,控制器的「行動」不必處理模型,即

ThingController < ApplicationController 
    def status 
    @status = system("#{Rails.root}/lib/mystatusscript"); 
    end 
end 

當URL訪問服務器,查詢路由表,並確定控制器和操作時,會調用操作。所以,如果你把這個在你的routes.rb:

match "/whatever" => "things#status" 

,並鍵入

http://localhost:3000/whatever 

在ThingsController(應用程序/控制器/ things_controller.rb)狀態的動作將被調用。

接下來會發生什麼,默認情況下,因爲你還沒有告訴它做任何事情,軌道將尋找應用程序/視圖/事/ status.html.erb,並使其,即:

The stats is <%= @status %> 

但是你可以防止這種情況,並進行軌道做別的事情,可能的例子:

ThingController < ApplicationController 
    def status 
    @status = system("#{Rails.root}/lib/mystatusscript"); 
    render :js=>"$('#status_retreived').show();" 
    end 
end 

ThingController < ApplicationController 
    def status 
    system("#{Rails.root}/lib/do_something_server_side"); 
    render :nothing=>true 
    end 
end 

ThingController < ApplicationController 
    def status 
    @status = system("#{Rails.root}/lib/mystatusscript"); 
    render action=>:edit 
    end 
end 

附加

讓我們做一個表格,看看會發生什麼

說你的應用程序/視圖/事/ edit.html.erb有這樣的:

<%= form_for @thing do |f| %> 
    <%= f.input :name %> 
    <%= f.submit %> 
<% end %> 

說你在routes.rb中這些路線:

get '/things/:id/edit' => 'things#edit' 
put '/things/:id/update' => 'things#update' 

而且你的控制器具有:

def update 
    @thing = Thing.find(params[:id]) 
    @thing.attributes = params[:thing] 
    @thing.save 
end 
def edit 
    @thing = Thing.find(params[:id]) 
end 

因此,這裏的流量,你打你的應用程序以 '/事/ 100 /編輯'

調用編輯操作,實例變量@thing設置爲ID爲100的記錄。然後呈現edit.html.erb視圖,向您顯示名稱字段和提交按鈕的編輯屏幕。

當你點擊「提交」,您將投入到「/事/ 100 /更新」

的,因爲其路由定義「/事/:ID /更新」的方式,當你進去的更新動作,則params [:編號]將包含100,而params [:東西]將包含什麼被張貼的形式,即您的PARAMS可以包含:

params[:thing][:name] 
params[:thing][:city] 
.... 
params[:thing][:zip] 

的ID被抽象到PARAMS [:ID ],表單數據爲參數[:東西]

更多

軌道做了很多自動生成的URL爲你的,這是它非常聰明,例如,在edit.html.erb,你有這樣的:

<%= form_for @thing do |f| %> 
    <%= f.input :name %> 
    <%= f.submit %> 
<% end %> 

如果你看一下HTML生成的你」我會看到類似的東西:

<form id="edit_thing_100" method="put" action="/things/100/update"> 

軌道如何知道做更新而不是創建?因爲它檢查了@thing並注意到它已經被保存到數據庫中,所以它不是新記錄,所以它必須是更新。

那麼在你看來,你通常創建不同的URI是那些獲得通過鏈接發送到服務器,提交按鈕等。當他們在routes.rb中擡起頭來,在適當的控制器適當的行動被調用。

文件上傳

也許比你想象的更容易,首先你需要稍微添加文件上傳字段和更改形式:

<%= form_for @thing do ,:html=>{:multipart=>true} |f| %> 
    <%= f.input :name %> 
    <%= f.file_field :upload %> 
    <%= f.submit %> 
<% end %> 

現在,當更新動作裏面你可以這樣做:

def update 
    filename = params[:thing][:upload].original_filename 
    filetype = params[:thing][:upload].content_type 
    filedata = params[:thing][:upload].read 

    File.open("#{Rails.root}/filestorage/#{filename}","wb") { |f| f.write(filedata) } 

    @thing = Thing.find(params[:id]) 

    @thing.attributes = params[:thing] 
    @thing.uploadstoredin = "#{Rails.root}/filestorage/#{filename}" 
    @thing.save 
end 

因爲你所做的形式多,你聲明的特性:上傳的是,file_field,當PARAMS張貼的:上傳PARAM有三個額外的我thods(original_filename,content_type和read),Rails MAGIC!

+0

那麼在涉及表單的情況下會發生什麼?如果我有一個上傳表單在我的應用程序/視圖/東西/ status.html.erb視圖 <(%)=的form_tag({:動作=>:上傳}:多=>真)做%> <%= file_field_tag '文件' %> <%= submit_tag '上傳' %> <% end %> 我點擊提交? params [:file]對象在哪裏去,我將在哪裏解析它的數據?對不起,這個醜陋的輸出。 – Utopia025 2013-02-20 22:59:43

+0

添加了一些更多解釋 – RadBrad 2013-02-20 23:27:05

+0

您指定的路線如何知道彼此進行交互?如何知道編輯表單將條目提交給更新操作? (非常感謝所有事情,到目前爲止,您一直非常樂於助人!!!) – Utopia025 2013-02-21 19:40:42

3

1)是的,當然,控制器根本不需要與任何模型一起工作,或者他們可以使用數千個模型。不要與scafolding混淆。控制器通常位於模型之上的事實是因爲它的主要責任是與該模型進行交互,但這不是規則。

2)Rack完成HTTP堆棧後,將其分派到您的路由(在config/routes.rb中定義),然後路由器將其分派到您在該文件中指定的控制器/方法。如果您想要查看當前應用中的所有路線,請輸入:「rake routes」。

控制器從機架接收參數。 http請求參數整齊地打包成一個散列併發送給你,你可以方便地使用params()方法訪問。除了閱讀它們之外,控制器對任何參數都沒有任何影響。

至於意見,他們不是由控制器派遣。當控制器調用render(),render_to_string(),render_with()等時,適當的視圖模板以及佈局(您可以指定或默認爲控制器)將被加載並處理(轉換爲一個字符串,然後通過HTTP響應發送出去)。這裏唯一的法寶,在控制器的實例變量是提供給意見(他們本身可以作爲實例變量使用)

我希望這清除了一些東西給你.. :)