2013-02-20 49 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响应发送出去)。这里唯一的法宝,在控制器的实例变量是提供给意见(他们本身可以作为实例变量使用)

我希望这清除了一些东西给你.. :)