Class: Gin::Controller
- Inherits:
-
Object
- Object
- Gin::Controller
- Extended by:
- GinClass
- Includes:
- Errorable, Filterable
- Defined in:
- lib/gin/controller.rb
Instance Attribute Summary collapse
-
#action ⇒ Object
readonly
Returns the value of attribute action.
-
#app ⇒ Object
readonly
Returns the value of attribute app.
-
#env ⇒ Object
readonly
Returns the value of attribute env.
-
#request ⇒ Object
readonly
Returns the value of attribute request.
-
#response ⇒ Object
readonly
Returns the value of attribute response.
Class Method Summary collapse
-
.actions ⇒ Object
Array of action names for this controller.
-
.content_type(new_type = nil) ⇒ Object
Set or get the default content type for this Gin::Controller.
-
.controller_name ⇒ Object
String representing the controller name.
-
.exec(app, env, &block) ⇒ Object
Execute arbitrary code in the context of a Gin::Controller instance.
Instance Method Summary collapse
-
#asset(path) ⇒ Object
Check if an asset exists.
-
#asset_url(name) ⇒ Object
Returns the url to an asset, including predefined asset cdn hosts if set.
-
#body(body = nil) ⇒ Object
Get or set the HTTP response body.
-
#cache_control(*values) ⇒ Object
Specify response freshness policy for HTTP caches (Cache-Control header).
-
#call_action(action) ⇒ Object
:nodoc:.
-
#content_type(type = nil, params = {}) ⇒ Object
Get or set the HTTP response Content-Type header.
-
#cookies ⇒ Object
Access the request cookies.
-
#dispatch(action) ⇒ Object
Dispatch the call to the action, calling before and after filers, and including error handling.
-
#error(code, body = nil) ⇒ Object
Halt processing and return the error status provided.
-
#etag(value, opts = {}) ⇒ Object
Set the ETag header.
-
#etag_matches?(list, new_resource = @request.post?) ⇒ Boolean
:nodoc:.
-
#expire_cache_control ⇒ Object
Sets Cache-Control, Expires, and Pragma headers to tell the browser not to cache the response.
-
#expires(amount, *values) ⇒ Object
Set the Expires header and Cache-Control/max-age directive.
-
#halt(*resp) ⇒ Object
Stop the execution of an action and return the response.
-
#headers(hash = nil) ⇒ Object
Set multiple response headers with Hash.
-
#html_error_page(err, code = nil) ⇒ Object
In development mode, returns an HTML page displaying the full error and backtrace, otherwise shows a generic error page.
-
#initialize(app, env) ⇒ Controller
constructor
A new instance of Controller.
-
#invoke ⇒ Object
Taken from Sinatra.
-
#last_modified(time) ⇒ Object
Set the last modified time of the resource (HTTP ‘Last-Modified’ header) and halt if conditional GET matches.
-
#logger ⇒ Object
Accessor for main application logger.
-
#mime_type(type) ⇒ Object
Get the normalized mime-type matching the given input.
-
#params ⇒ Object
Get the request params.
-
#path_to(*args) ⇒ Object
Build a path to the given controller and action or route name, with any expected params.
-
#redirect(uri, *args) ⇒ Object
Send a 301, 302, or 303 redirect and halt.
-
#send_file(path, opts = {}) ⇒ Object
Assigns a file to the response body and halts the execution of the action.
-
#session ⇒ Object
Access the request session.
-
#set_cookie(name, value = nil, opts = {}) ⇒ Object
Set a cookie on the Rack response.
-
#status(code = nil) ⇒ Object
Set or get the HTTP response status code.
-
#stream(keep_open = false, &block) ⇒ Object
Assigns a Gin::Stream to the response body, which is yielded to the block.
- #url_to(*args) ⇒ Object (also: #to)
Methods included from Errorable
#handle_error, #handle_status, included
Methods included from Filterable
Constructor Details
Instance Attribute Details
#action ⇒ Object (readonly)
Returns the value of attribute action.
59 60 61 |
# File 'lib/gin/controller.rb', line 59 def action @action end |
#app ⇒ Object (readonly)
Returns the value of attribute app.
59 60 61 |
# File 'lib/gin/controller.rb', line 59 def app @app end |
#env ⇒ Object (readonly)
Returns the value of attribute env.
59 60 61 |
# File 'lib/gin/controller.rb', line 59 def env @env end |
#request ⇒ Object (readonly)
Returns the value of attribute request.
59 60 61 |
# File 'lib/gin/controller.rb', line 59 def request @request end |
#response ⇒ Object (readonly)
Returns the value of attribute response.
59 60 61 |
# File 'lib/gin/controller.rb', line 59 def response @response end |
Class Method Details
.actions ⇒ Object
Array of action names for this controller.
18 19 20 |
# File 'lib/gin/controller.rb', line 18 def self.actions instance_methods(false) end |
.content_type(new_type = nil) ⇒ Object
Set or get the default content type for this Gin::Controller. Default value is “text/html”. This attribute is inherited.
38 39 40 41 42 43 |
# File 'lib/gin/controller.rb', line 38 def self.content_type new_type=nil return @content_type = new_type if new_type return @content_type if @content_type self.superclass.respond_to?(:content_type) ? self.superclass.content_type.dup : "text/html" end |
.controller_name ⇒ Object
String representing the controller name. Underscores the class name and removes mentions of ‘controller’.
MyApp::FooController.controller_name
#=> "my_app/foo"
29 30 31 |
# File 'lib/gin/controller.rb', line 29 def self.controller_name @ctrl_name ||= Gin.underscore(self.to_s).gsub(/_?controller_?/,'') end |
.exec(app, env, &block) ⇒ Object
Execute arbitrary code in the context of a Gin::Controller instance. Returns a Rack response Array.
50 51 52 53 54 |
# File 'lib/gin/controller.rb', line 50 def self.exec app, env, &block inst = new(app, env) inst.invoke{ inst.instance_exec(&block) } inst.response.finish end |
Instance Method Details
#asset(path) ⇒ Object
Check if an asset exists. Returns the full system path to the asset if found, otherwise nil.
502 503 504 |
# File 'lib/gin/controller.rb', line 502 def asset path @app.asset path end |
#asset_url(name) ⇒ Object
Returns the url to an asset, including predefined asset cdn hosts if set.
491 492 493 494 495 |
# File 'lib/gin/controller.rb', line 491 def asset_url name url = File.join(@app.asset_host_for(name).to_s, name) url = [url, *@app.asset_version(url)].join("?") if url !~ %r{^https?://} url end |
#body(body = nil) ⇒ Object
Get or set the HTTP response body.
92 93 94 95 |
# File 'lib/gin/controller.rb', line 92 def body body=nil @response.body = body if body @response.body end |
#cache_control(*values) ⇒ Object
Specify response freshness policy for HTTP caches (Cache-Control header). Any number of non-value directives (:public, :private, :no_cache, :no_store, :must_revalidate, :proxy_revalidate) may be passed along with a Hash of value directives (:max_age, :min_stale, :s_max_age).
cache_control :public, :must_revalidate, :max_age => 60
#=> Cache-Control: public, must-revalidate, max-age=60
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
# File 'lib/gin/controller.rb', line 430 def cache_control *values if Hash === values.last hash = values.pop hash.reject!{|k,v| v == false || v == true && values << k } else hash = {} end values.map! { |value| value.to_s.tr('_','-') } hash.each do |key, value| key = key.to_s.tr('_', '-') value = value.to_i if key == "max-age" values << [key, value].join('=') end @response['Cache-Control'] = values.join(', ') if values.any? end |
#call_action(action) ⇒ Object
:nodoc:
71 72 73 74 75 76 77 |
# File 'lib/gin/controller.rb', line 71 def call_action action #:nodoc: invoke{ dispatch action } invoke{ handle_status(@response.status) } content_type self.class.content_type unless @response[Gin::Response::H_CTYPE] @response.finish end |
#content_type(type = nil, params = {}) ⇒ Object
Get or set the HTTP response Content-Type header.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/gin/controller.rb', line 109 def content_type type=nil, params={} return @response[Gin::Response::H_CTYPE] unless type default = params.delete(:default) mime_type = mime_type(type) || default raise "Unknown media type: %p" % type if mime_type.nil? mime_type = mime_type.dup unless params.include? :charset params[:charset] = params.delete('charset') || 'UTF-8' end params.delete :charset if mime_type.include? 'charset' unless params.empty? mime_type << (mime_type.include?(';') ? ', ' : ';') mime_type << params.map do |key, val| val = val.inspect if val =~ /[";,]/ "#{key}=#{val}" end.join(', ') end @response[Gin::Response::H_CTYPE] = mime_type end |
#cookies ⇒ Object
Access the request cookies.
251 252 253 |
# File 'lib/gin/controller.rb', line 251 def @request. end |
#dispatch(action) ⇒ Object
Dispatch the call to the action, calling before and after filers, and including error handling.
531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'lib/gin/controller.rb', line 531 def dispatch action @action = action invoke do filter(*before_filters_for(action)) args = action_arguments action __send__(action, *args) end rescue => err invoke{ handle_error err } ensure filter(*after_filters_for(action)) end |
#error(code, body = nil) ⇒ Object
Halt processing and return the error status provided.
155 156 157 158 159 |
# File 'lib/gin/controller.rb', line 155 def error code, body=nil code, body = 500, code if code.respond_to? :to_str @response.body = body unless body.nil? halt code end |
#etag(value, opts = {}) ⇒ Object
Set the ETag header. If the ETag was set in a previous request and matches the current one, halts the action and returns a 304 on GET and HEAD requests.
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/gin/controller.rb', line 167 def etag value, opts={} opts = {:kind => opts} unless Hash === opts kind = opts[:kind] || :strong new_resource = opts.fetch(:new_resource) { @request.post? } unless [:strong, :weak].include?(kind) raise ArgumentError, ":strong or :weak expected" end value = '"%s"' % value value = 'W/' + value if kind == :weak @response['ETag'] = value if (200..299).include?(status) || status == 304 if etag_matches? @env['HTTP_IF_NONE_MATCH'], new_resource halt(@request.safe? ? 304 : 412) end if @env['HTTP_IF_MATCH'] halt 412 unless etag_matches? @env['HTTP_IF_MATCH'], new_resource end end end |
#etag_matches?(list, new_resource = @request.post?) ⇒ Boolean
:nodoc:
192 193 194 195 |
# File 'lib/gin/controller.rb', line 192 def etag_matches? list, new_resource=@request.post? #:nodoc: return !new_resource if list == '*' list.to_s.split(/\s*,\s*/).include? response['ETag'] end |
#expire_cache_control ⇒ Object
Sets Cache-Control, Expires, and Pragma headers to tell the browser not to cache the response.
481 482 483 484 485 |
# File 'lib/gin/controller.rb', line 481 def expire_cache_control @response['Pragma'] = 'no-cache' expires Time.new("1990","01","01"), :no_cache, :no_store, :must_revalidate, max_age: 0 end |
#expires(amount, *values) ⇒ Object
Set the Expires header and Cache-Control/max-age directive. Amount can be an integer number of seconds in the future or a Time object indicating when the response should be considered “stale”. The remaining “values” arguments are passed to the #cache_control helper:
expires 500, :public, :must_revalidate
=> Cache-Control: public, must-revalidate, max-age=60
=> Expires: Mon, 08 Jun 2009 08:50:17 GMT
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
# File 'lib/gin/controller.rb', line 459 def expires amount, *values values << {} unless Hash === values.last if Integer === amount time = Time.now + amount.to_i max_age = amount else time = String === amount ? Time.parse(amount) : amount max_age = time - Time.now end values.last.merge!(:max_age => max_age) unless values.last[:max_age] cache_control(*values) @response['Expires'] = time.httpdate end |
#halt(*resp) ⇒ Object
Stop the execution of an action and return the response. May be given a status code, string, header Hash, or a combination:
halt 400, "Badly formed request"
halt "Done early! WOOO!"
halt 302, {'Location' => 'http://example.com'}, "You are being redirected"
141 142 143 144 145 146 147 148 149 |
# File 'lib/gin/controller.rb', line 141 def halt *resp if @app.development? line = caller.find{|l| !l.start_with?(Gin::LIB_DIR) && !l.include?("/ruby/gems/")} logger << "[HALT] #{line}\n" if line end resp = resp.first if resp.length == 1 throw :halt, resp end |
#headers(hash = nil) ⇒ Object
Set multiple response headers with Hash.
203 204 205 206 |
# File 'lib/gin/controller.rb', line 203 def headers hash=nil @response.headers.merge! hash if hash @response.headers end |
#html_error_page(err, code = nil) ⇒ Object
In development mode, returns an HTML page displaying the full error and backtrace, otherwise shows a generic error page.
Production error pages are first looked for in the public directory as <status>.html or 500.html. If none is found, falls back on Gin’s internal error html pages.
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 |
# File 'lib/gin/controller.rb', line 555 def html_error_page err, code=nil if @app.development? fulltrace = err.backtrace.join("\n") fulltrace = "<pre>#{fulltrace}</pre>" apptrace = Gin.app_trace(err.backtrace).join("\n") apptrace = "<pre>#{apptrace}</pre>" unless apptrace.empty? DEV_ERROR_HTML % [err.class, err.class, err., apptrace, fulltrace] else code ||= status filepath = asset("#{code}.html") || asset("500.html") unless filepath filepath = File.join(Gin::PUBLIC_DIR, "#{code}.html") filepath = File.join(Gin::PUBLIC_DIR, "500.html") if !File.file?(filepath) end File.open(filepath, "rb") end end |
#invoke ⇒ Object
Taken from Sinatra.
Run the block with ‘throw :halt’ support and apply result to the response.
512 513 514 515 516 517 518 519 520 521 522 523 524 |
# File 'lib/gin/controller.rb', line 512 def invoke res = catch(:halt) { yield } res = [res] if Fixnum === res || String === res if Array === res && Fixnum === res.first res = res.dup status(res.shift) body(res.pop) headers(*res) elsif res.respond_to? :each body res end nil # avoid double setting the same response tuple twice end |
#last_modified(time) ⇒ Object
Set the last modified time of the resource (HTTP ‘Last-Modified’ header) and halt if conditional GET matches. The time
argument is a Time, DateTime, or other object that responds to to_time
or httpdate
.
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
# File 'lib/gin/controller.rb', line 394 def last_modified time return unless time time = Time.at(time) if Integer === time time = Time.parse(time) if String === time time = time.to_time if time.respond_to?(:to_time) @response['Last-Modified'] = time.httpdate return if @env['HTTP_IF_NONE_MATCH'] if status == 200 && @env['HTTP_IF_MODIFIED_SINCE'] # compare based on seconds since epoch since = Time.httpdate(@env['HTTP_IF_MODIFIED_SINCE']).to_i halt 304 if since >= time.to_i end if @env['HTTP_IF_UNMODIFIED_SINCE'] && ((200..299).include?(status) || status == 412) # compare based on seconds since epoch since = Time.httpdate(@env['HTTP_IF_UNMODIFIED_SINCE']).to_i halt 412 if since < time.to_i end rescue ArgumentError end |
#logger ⇒ Object
Accessor for main application logger.
227 228 229 |
# File 'lib/gin/controller.rb', line 227 def logger @app.logger end |
#mime_type(type) ⇒ Object
Get the normalized mime-type matching the given input.
101 102 103 |
# File 'lib/gin/controller.rb', line 101 def mime_type type @app.mime_type type end |
#params ⇒ Object
Get the request params.
235 236 237 |
# File 'lib/gin/controller.rb', line 235 def params @request.params end |
#path_to(*args) ⇒ Object
Build a path to the given controller and action or route name, with any expected params. If no controller is specified and the current controller responds to the symbol given, uses the current controller for path lookup.
path_to FooController, :show, :id => 123
#=> "/foo/123"
# From FooController
path_to :show, :id => 123
#=> "/foo/123"
path_to :show_foo, :id => 123
#=> "/foo/123"
289 290 291 292 293 |
# File 'lib/gin/controller.rb', line 289 def path_to *args return "#{args[0]}#{"?" << Gin.build_query(args[1]) if args[1]}" if String === args[0] args.unshift(self.class) if Symbol === args[0] && respond_to?(args[0]) @app.router.path_to(*args) end |
#redirect(uri, *args) ⇒ Object
Send a 301, 302, or 303 redirect and halt. Supports passing a full URI, partial path.
redirect "http://google.com"
redirect "/foo"
redirect "/foo", 301, "You are being redirected..."
redirect to(MyController, :action, :id => 123)
redirect to(:show_foo, :id => 123)
346 347 348 349 350 351 352 353 354 355 |
# File 'lib/gin/controller.rb', line 346 def redirect uri, *args if @env['HTTP_VERSION'] == 'HTTP/1.1' && @env["REQUEST_METHOD"] != 'GET' status 303 else status 302 end @response['Location'] = url_to(uri.to_s) halt(*args) end |
#send_file(path, opts = {}) ⇒ Object
Assigns a file to the response body and halts the execution of the action. Produces a 404 response if no file is found.
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 |
# File 'lib/gin/controller.rb', line 362 def send_file path, opts={} if opts[:type] || !@response[Gin::Response::H_CTYPE] content_type opts[:type] || File.extname(path), :default => 'application/octet-stream' end disposition = opts[:disposition] filename = opts[:filename] disposition = 'attachment' if disposition.nil? && filename filename = File.basename(path) if filename.nil? if disposition @response['Content-Disposition'] = "%s; filename=\"%s\"" % [disposition, filename] end last_modified opts[:last_modified] || File.mtime(path).httpdate halt 200 if @request.head? @response['Content-Length'] = File.size?(path).to_s halt 200, File.open(path, "rb") rescue Errno::ENOENT halt 404 end |
#session ⇒ Object
Access the request session.
243 244 245 |
# File 'lib/gin/controller.rb', line 243 def session @request.session end |
#set_cookie(name, value = nil, opts = {}) ⇒ Object
Set a cookie on the Rack response.
"mycookie", "FOO", :expires => 600, :path => "/"
"mycookie", :expires => 600
262 263 264 265 266 267 268 269 270 |
# File 'lib/gin/controller.rb', line 262 def name, value=nil, opts={} if Hash === value opts = value else opts[:value] = value end @response. name, opts end |
#status(code = nil) ⇒ Object
Set or get the HTTP response status code.
83 84 85 86 |
# File 'lib/gin/controller.rb', line 83 def status code=nil @response.status = code if code @response.status end |
#stream(keep_open = false, &block) ⇒ Object
Assigns a Gin::Stream to the response body, which is yielded to the block. The block execution is delayed until the action returns.
stream do |io|
file = File.open "somefile", "rb"
io << file.read(1024) until file.eof?
file.close
end
218 219 220 221 |
# File 'lib/gin/controller.rb', line 218 def stream keep_open=false, &block scheduler = env['async.callback'] ? EventMachine : Gin::Stream body Gin::Stream.new(scheduler, keep_open){ |out| yield(out) } end |
#url_to(*args) ⇒ Object Also known as: to
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/gin/controller.rb', line 315 def url_to *args path = path_to(*args) return path if path =~ /\A[A-z][A-z0-9\+\.\-]*:/ uri = [host = ""] host << "http#{'s' if @request.ssl?}://" if @request.forwarded? || @request.port != (@request.ssl? ? 443 : 80) host << @request.host_with_port else host << @request.host end uri << @request.script_name.to_s uri << path File.join uri end |