1) Yes absolutely, a controller 'action' does NOT have to deal with a model, i.e.
ThingController < ApplicationController
def status
@status = system("#{Rails.root}/lib/mystatusscript");
end
end
Actions are called when a URL hits the server, and the routing table is consulted, and a controller and action are determined. So if you put this in your routes.rb:
match "/whatever" => "things#status"
and type
http://localhost:3000/whatever
The status action in the ThingsController (app/controllers/things_controller.rb) will get called.
What happens next, by default, because you've not told it to do anything else, rails will look for app/views/things/status.html.erb, and render it, i.e.:
The stats is <%= @status %>
But you can prevent that, and make rails do something else, possible examples:
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
ADDITIONAL
Let's make a form and see what happens
Say you have this in app/views/things/edit.html.erb:
<%= form_for @thing do |f| %>
<%= f.input :name %>
<%= f.submit %>
<% end %>
Say you have these routes in routes.rb:
get '/things/:id/edit' => 'things#edit'
put '/things/:id/update' => 'things#update'
And your controller has:
def update
@thing = Thing.find(params[:id])
@thing.attributes = params[:thing]
@thing.save
end
def edit
@thing = Thing.find(params[:id])
end
So here is the flow, you hit your app with '/things/100/edit'
The edit action is called , the instance variable @thing is set to the record who's id is 100. Then the edit.html.erb view is rendered, presenting you with an edit screen for the name field and a submit button.
When you click 'submit', you will PUT to '/things/100/update'
Because of the way the route was defined '/things/:id/update', when you get inside the update action, params[:id] will contain 100, AND params[:thing] will contain what was posted by the form, i.e. your params could contain:
params[:thing][:name]
params[:thing][:city]
....
params[:thing][:zip]
The ID is abstracted out into params[:id], and the form data is in params[:thing]
MORE
rails does a lot of automatic url generation for you, it's very smart about it, for example, in edit.html.erb, you have this:
<%= form_for @thing do |f| %>
<%= f.input :name %>
<%= f.submit %>
<% end %>
If you look at the HTML generated you'll see something like:
<form id="edit_thing_100" method="put" action="/things/100/update">
How did rails KNOW to do an update instead of a create? Because it checked @thing and noticed it had already been saved to the database prior, it's NOT a new record, so it must be an update.
So in your view you typically create various URI's that get sent to the server via links , submit buttons, etc. When they are looked up in routes.rb, the appropriate action in the appropriate controller is called.
FILE UPLOAD
Is easier than you may think, first you need to add the file upload field AND change the form slightly:
<%= form_for @thing do ,:html=>{:multipart=>true} |f| %>
<%= f.input :name %>
<%= f.file_field :upload %>
<%= f.submit %>
<% end %>
Now, when inside the update action you can do this:
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
Because you made the form multipart, and you declared an attribute :upload as a file_field, when the params are posted, the :upload param has three extra methods (original_filename, content_type and read), Rails MAGIC!