Class: Gin::Controller
- Inherits:
-
Object
- Object
- Gin::Controller
- Includes:
- Constants, Errorable, Filterable
- Defined in:
- lib/gin/controller.rb
Overview
Gin controllers follow only a few rules:
* ALL instance methods are actions (put your helper methods in a module or
parent class not mounted to the app).
* Filters are defined by blocks passed to special class methods.
* Controller-level error handlers are defined by blocks passed to the 'error'
class method.
Gin controller actions are any instance method defined on the controller
class. The HTTP response body takes the value of the method's return value.
If the instance method takes arguments, matching params will be assigned to
them. A required argument with a missing param triggers a Gin::BadRequest
error, resulting in a 400 response.
class UserController < Gin::Controller
# Get params id and email
def show id, email=nil
...
end
end
Gin actions also support Ruby 2.0 keyed arguments, which are more flexible
for assigning default values when dealing with missing params.
class UserController < Gin::Controller
def show(id, email: nil, full: false)
...
end
end
Views are rendered by calling the 'view' method from a controller instance.
Views don't halt the action but return a String of the rendered view.
If a layout was set, the rendered view will include the layout.
class UserController < Gin::Controller
layout :user
def show id
# Renders <app.views_dir>/show_user.* with the layout <app.layouts_dir>/user.*
view :show_user
end
def tos
# Renders <app.views_dir>/tos.* with no layout
view :tos, :layout => false
end
end
Constant Summary collapse
- DEFAULT_ACTION_MAP =
{ :index => %w{GET /}, :show => %w{GET /:id}, :new => %w{GET /new}, :create => %w{POST /}, :edit => %w{GET /:id/edit}, :update => %w{PUT /:id}, :destroy => %w{DELETE /:id} }
Constants included from Constants
Gin::Constants::ASYNC_CALLBACK, Gin::Constants::CACHE_CTRL, Gin::Constants::CNT_DISPOSITION, Gin::Constants::CNT_LENGTH, Gin::Constants::CNT_TYPE, Gin::Constants::ENV_DEV, Gin::Constants::ENV_PROD, Gin::Constants::ENV_STAGE, Gin::Constants::ENV_TEST, Gin::Constants::EPOCH, Gin::Constants::ETAG, Gin::Constants::EXPIRES, Gin::Constants::FWD_FOR, Gin::Constants::FWD_HOST, Gin::Constants::GIN_APP, Gin::Constants::GIN_CTRL, Gin::Constants::GIN_ERRORS, Gin::Constants::GIN_PATH_PARAMS, Gin::Constants::GIN_RELOADED, Gin::Constants::GIN_ROUTE, Gin::Constants::GIN_STACK, Gin::Constants::GIN_STATIC, Gin::Constants::GIN_TARGET, Gin::Constants::GIN_TEMPLATES, Gin::Constants::GIN_TIMESTAMP, Gin::Constants::HOST_NAME, Gin::Constants::HTTP_VERSION, Gin::Constants::IF_MATCH, Gin::Constants::IF_MOD_SINCE, Gin::Constants::IF_NONE_MATCH, Gin::Constants::IF_UNMOD_SINCE, Gin::Constants::LAST_MOD, Gin::Constants::LOCATION, Gin::Constants::PATH_INFO, Gin::Constants::PRAGMA, Gin::Constants::QUERY_STRING, Gin::Constants::RACK_INPUT, Gin::Constants::REMOTE_ADDR, Gin::Constants::REMOTE_USER, Gin::Constants::REQ_METHOD, Gin::Constants::SERVER_NAME, Gin::Constants::SERVER_PORT, Gin::Constants::SESSION_SECRET
Instance Attribute Summary collapse
-
#action ⇒ Object
readonly
The action that the HTTP request resolved to, based on the App’s router.
-
#app ⇒ Object
readonly
The Gin::App instance used by the controller.
-
#env ⇒ Object
readonly
The Rack env hash.
-
#request ⇒ Object
readonly
Gin::Request instance representing the HTTP request.
-
#response ⇒ Object
readonly
Gin::Response instance representing the HTTP response.
Class Method Summary collapse
-
.actions ⇒ Object
Array of action names for this controller.
-
.autocast_params(arg = nil) ⇒ Object
Define if params should be cast to autodetected types.
-
.call(env) ⇒ Object
Call the Controller with an Rack env hash.
-
.content_type(new_type = nil) ⇒ Object
Set or get the default content type for this Gin::Controller.
-
.controller_name(new_name = nil) ⇒ Object
String representing the controller name.
-
.default_route_for(action) ⇒ Object
:nodoc:.
-
.display_name(action = nil) ⇒ Object
:nodoc:.
-
.exec(app, env, &block) ⇒ Object
Execute arbitrary code in the context of a Gin::Controller instance.
- .inherited(subclass) ⇒ Object
-
.layout(name = nil) ⇒ Object
Get or set a layout for a given controller.
-
.route_name_for(action) ⇒ Object
:nodoc:.
-
.setup ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#asset(path) ⇒ Object
Check if an asset exists.
-
#asset_path(name) ⇒ Object
Returns the HTTP path to the local asset.
-
#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 = nil) ⇒ Object
Calls the given or preset action and returns a Rack response Array.
-
#config ⇒ Object
Accessor for @app.config.
-
#content_type(type = nil, params = {}) ⇒ Object
Get or set the HTTP response Content-Type header.
-
#cookies ⇒ Object
Access the request cookies.
-
#delete_cookie(name) ⇒ Object
Delete the response cookie with the given name.
-
#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.
-
#h(obj) ⇒ Object
HTML-escape the given String.
-
#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.
-
#layout ⇒ Object
Value of the layout to use for rendering.
-
#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.
-
#reroute(*args) ⇒ Object
Unlike Gin::Controller#rewrite, the reroute method forwards the current request and params to the provided controller and/or action, or named route.
-
#rewrite(*args) ⇒ Object
Halt execution of the current controller action and create a new request to another action and/or controller, or path.
-
#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.
-
#template_path(template, is_layout = false) ⇒ Object
Returns the path to where the template is expected to be.
- #url_to(*args) ⇒ Object (also: #to)
-
#view(template, opts = {}, &block) ⇒ Object
Render a template with the given view template.
Methods included from Mountable
actions, controller_name, default_route_for, display_name, route_name_for, verify_mount!
Methods included from Errorable
#handle_error, #handle_status, included
Methods included from Filterable
Constructor Details
#initialize(app, env) ⇒ Controller
Returns a new instance of Controller.
243 244 245 246 247 248 249 250 |
# File 'lib/gin/controller.rb', line 243 def initialize app, env @app = app @action = nil @env = env @request = Gin::Request.new env @response = Gin::Response.new @request.autocast_params = self.class.autocast_params end |
Instance Attribute Details
#action ⇒ Object (readonly)
The action that the HTTP request resolved to, based on the App’s router.
237 238 239 |
# File 'lib/gin/controller.rb', line 237 def action @action end |
#app ⇒ Object (readonly)
The Gin::App instance used by the controller. The App instance is meant for read-only use. Writes are not thread-safe and at your own risk.
228 229 230 |
# File 'lib/gin/controller.rb', line 228 def app @app end |
#env ⇒ Object (readonly)
The Rack env hash.
240 241 242 |
# File 'lib/gin/controller.rb', line 240 def env @env end |
#request ⇒ Object (readonly)
Gin::Request instance representing the HTTP request.
231 232 233 |
# File 'lib/gin/controller.rb', line 231 def request @request end |
#response ⇒ Object (readonly)
Gin::Response instance representing the HTTP response.
234 235 236 |
# File 'lib/gin/controller.rb', line 234 def response @response end |
Class Method Details
.actions ⇒ Object
Array of action names for this controller.
89 90 91 |
# File 'lib/gin/controller.rb', line 89 def self.actions instance_methods(false).map{|a| a.to_sym } end |
.autocast_params(arg = nil) ⇒ Object
Define if params should be cast to autodetected types. This is an inherited attribute.
-
Passing a boolean turns auto-casting on or off for all params.
-
Passing a hash with :only or :except limits auto-casting to the given param names
By default all params are cast to their autodetected types.
autocast_params true # enabled for all params
autocast_params false # disabled for all params
autocast_params except: [:zip, :phone, :fax]
autocast_params only: [:timestamp, :age]
Params get cast as follows:
* TrueClass true
* FalseClass: false
* Fixnum: 1234, -1234
* Float: 1.123, -1.123
* String: Everything else, including numbers that start with a 0
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/gin/controller.rb', line 203 def self.autocast_params arg=nil if Hash === arg && Hash === @autocast_params arg.each do |k, v| if @autocast_params[k] @autocast_params[k] |= [*v] else @autocast_params[k] = [*v] end end elsif arg == true || arg == false @autocast_params = arg elsif Hash === arg @autocast_params = arg.dup end return @autocast_params end |
.call(env) ⇒ Object
Call the Controller with an Rack env hash. Requires the hash to have the keys ‘gin.target’ with the action name as the second item of the array, and ‘gin.app’.
163 164 165 166 167 |
# File 'lib/gin/controller.rb', line 163 def self.call env inst = new(env[GIN_APP], env) env[GIN_CTRL] = inst inst.call_action(env[GIN_TARGET][1]) 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.
139 140 141 142 143 144 |
# File 'lib/gin/controller.rb', line 139 def self.content_type new_type=nil @content_type = new_type if new_type return @content_type if defined?(@content_type) && @content_type self.superclass.respond_to?(:content_type) && self.superclass.content_type || "text/html" end |
.controller_name(new_name = nil) ⇒ Object
String representing the controller name. Underscores the class name and removes mentions of ‘controller’.
MyApp::FooController.controller_name
#=> "my_app/foo"
Note that when route names get autogenerated, the namespacing is dropped. If two routes have the same name, the last one defined wins.
103 104 105 106 |
# File 'lib/gin/controller.rb', line 103 def self.controller_name new_name=nil @ctrl_name = new_name if new_name @ctrl_name end |
.default_route_for(action) ⇒ Object
:nodoc:
120 121 122 |
# File 'lib/gin/controller.rb', line 120 def self.default_route_for action #:nodoc: DEFAULT_ACTION_MAP[action] || ['GET', "/#{action}"] end |
.display_name(action = nil) ⇒ Object
:nodoc:
130 131 132 |
# File 'lib/gin/controller.rb', line 130 def self.display_name action=nil #:nodoc: [self, action].compact.join("#") end |
.exec(app, env, &block) ⇒ Object
Execute arbitrary code in the context of a Gin::Controller instance. Returns a Rack response Array.
151 152 153 154 155 |
# File 'lib/gin/controller.rb', line 151 def self.exec app, env, &block inst = new(app, env) inst.invoke{ inst.instance_exec(&block) } inst.response.finish end |
.inherited(subclass) ⇒ Object
70 71 72 73 74 |
# File 'lib/gin/controller.rb', line 70 def self.inherited subclass subclass.setup subclass.autocast_params self.autocast_params super end |
.layout(name = nil) ⇒ Object
Get or set a layout for a given controller. Value can be a symbol or filepath. Layout file is expected to be in the Gin::App.layout_dir directory Defaults to the parent class layout, or Gin::App.layout.
176 177 178 179 180 |
# File 'lib/gin/controller.rb', line 176 def self.layout name=nil @layout = name if name return @layout if @layout return self.superclass.layout if self.superclass.respond_to?(:layout) end |
.route_name_for(action) ⇒ Object
:nodoc:
125 126 127 |
# File 'lib/gin/controller.rb', line 125 def self.route_name_for action #:nodoc: "#{action}_#{controller_name.sub(%r{^.*/},'')}".to_sym end |
.setup ⇒ Object
:nodoc:
77 78 79 80 81 |
# File 'lib/gin/controller.rb', line 77 def self.setup # :nodoc: @layout = nil @autocast_params = true @ctrl_name = Gin.underscore(self.to_s).gsub(/_?controller_?/,'') end |
Instance Method Details
#asset(path) ⇒ Object
Check if an asset exists. Returns the full system path to the asset if found, otherwise nil.
820 821 822 |
# File 'lib/gin/controller.rb', line 820 def asset path @app.asset path end |
#asset_path(name) ⇒ Object
Returns the HTTP path to the local asset.
800 801 802 803 804 805 806 807 808 809 810 811 812 813 |
# File 'lib/gin/controller.rb', line 800 def asset_path name fdpath = @app.asset(name) if fdpath && fdpath.start_with?(@app.assets_dir) if fdpath.start_with?(@app.public_dir) fdpath[@app.public_dir.length..-1] else fdpath[@app.assets_dir.length..-1] end else path = File.join('', name) [path, *@app.asset_version(name)].compact.join("?") end end |
#asset_url(name) ⇒ Object
Returns the url to an asset, including predefined asset cdn hosts if set.
790 791 792 793 794 |
# File 'lib/gin/controller.rb', line 790 def asset_url name host = @app.asset_host_for(name) return asset_path(name) if !host File.join(host, name) end |
#body(body = nil) ⇒ Object
Get or set the HTTP response body.
277 278 279 280 |
# File 'lib/gin/controller.rb', line 277 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
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 |
# File 'lib/gin/controller.rb', line 730 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_CTRL] = values.join(', ') if values.any? end |
#call_action(action = nil) ⇒ Object
Calls the given or preset action and returns a Rack response Array.
256 257 258 259 260 261 262 |
# File 'lib/gin/controller.rb', line 256 def call_action action=nil action ||= @action invoke{ dispatch action } invoke{ handle_status(@response.status) } content_type self.class.content_type unless @response[CNT_TYPE] @response.finish end |
#config ⇒ Object
Accessor for @app.config.
286 287 288 |
# File 'lib/gin/controller.rb', line 286 def config @app.config end |
#content_type(type = nil, params = {}) ⇒ Object
Get or set the HTTP response Content-Type header.
content_type :json
content_type 'application/json;charset=us-ascii'
content_type :json, charset: 'us-ascii'
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/gin/controller.rb', line 305 def content_type type=nil, params={} return @response[CNT_TYPE] 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[CNT_TYPE] = mime_type end |
#cookies ⇒ Object
Access the request cookies.
445 446 447 |
# File 'lib/gin/controller.rb', line 445 def @request. end |
#delete_cookie(name) ⇒ Object
Delete the response cookie with the given name. Does not affect request cookies.
471 472 473 |
# File 'lib/gin/controller.rb', line 471 def name @response. name end |
#dispatch(action) ⇒ Object
Dispatch the call to the action, calling before and after filers, and including error handling.
945 946 947 948 949 950 951 952 953 954 955 956 957 958 |
# File 'lib/gin/controller.rb', line 945 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.
351 352 353 354 355 |
# File 'lib/gin/controller.rb', line 351 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.
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/gin/controller.rb', line 363 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[IF_NONE_MATCH], new_resource halt(@request.safe? ? 304 : 412) end if @env[IF_MATCH] halt 412 unless etag_matches? @env[IF_MATCH], new_resource end end end |
#etag_matches?(list, new_resource = @request.post?) ⇒ Boolean
:nodoc:
388 389 390 391 |
# File 'lib/gin/controller.rb', line 388 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.
781 782 783 784 |
# File 'lib/gin/controller.rb', line 781 def expire_cache_control @response[PRAGMA] = 'no-cache' expires EPOCH, :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
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 |
# File 'lib/gin/controller.rb', line 759 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 |
#h(obj) ⇒ Object
HTML-escape the given String.
998 999 1000 |
# File 'lib/gin/controller.rb', line 998 def h obj CGI.escapeHTML obj.to_s 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"
337 338 339 340 341 342 343 344 345 |
# File 'lib/gin/controller.rb', line 337 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.
397 398 399 400 |
# File 'lib/gin/controller.rb', line 397 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.
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 |
# File 'lib/gin/controller.rb', line 969 def html_error_page err, code=nil if @app.development? backtrace = err.backtrace || ['No backtrace :('] fulltrace = backtrace.join("\n") fulltrace = "<pre>#{h(fulltrace)}</pre>" apptrace = Gin.app_trace(backtrace).join("\n") apptrace = "<pre>#{h(apptrace)}</pre>" unless apptrace.empty? DEV_ERROR_HTML % [h(err.class), h(err.class), h(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.
926 927 928 929 930 931 932 933 934 935 936 937 938 |
# File 'lib/gin/controller.rb', line 926 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
.
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 |
# File 'lib/gin/controller.rb', line 688 def last_modified time return unless time time = if Integer === time Time.at(time) elsif time.respond_to?(:to_time) time.to_time elsif !time.is_a?(Time) Time.parse time.to_s else time end @response[LAST_MOD] = time.httpdate return if @env[IF_NONE_MATCH] if status == 200 && @env[IF_MOD_SINCE] # compare based on seconds since epoch since = Time.httpdate(@env[IF_MOD_SINCE]).to_i halt 304 if since >= time.to_i end if @env[IF_UNMOD_SINCE] && ((200..299).include?(status) || status == 412) # compare based on seconds since epoch since = Time.httpdate(@env[IF_UNMOD_SINCE]).to_i halt 412 if since < time.to_i end rescue ArgumentError end |
#layout ⇒ Object
Value of the layout to use for rendering. See also Gin::Controller.layout and Gin::App.layout.
829 830 831 |
# File 'lib/gin/controller.rb', line 829 def layout self.class.layout || @app.layout end |
#logger ⇒ Object
Accessor for main application logger.
421 422 423 |
# File 'lib/gin/controller.rb', line 421 def logger @app.logger end |
#mime_type(type) ⇒ Object
Get the normalized mime-type matching the given input.
294 295 296 |
# File 'lib/gin/controller.rb', line 294 def mime_type type @app.mime_type type end |
#params ⇒ Object
Get the request params.
429 430 431 |
# File 'lib/gin/controller.rb', line 429 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"
# Default named route
path_to :show_foo, :id => 123
#=> "/foo/123"
493 494 495 496 497 498 |
# File 'lib/gin/controller.rb', line 493 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] && self.class.actions.include?(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)
551 552 553 554 555 556 557 558 559 560 |
# File 'lib/gin/controller.rb', line 551 def redirect uri, *args if @env[HTTP_VERSION] == 'HTTP/1.1' && @env[REQ_METHOD] != 'GET' status 303 else status 302 end @response[LOCATION] = url_to(uri.to_s) halt(*args) end |
#reroute(*args) ⇒ Object
Unlike Gin::Controller#rewrite, the reroute method forwards the current request and params to the provided controller and/or action, or named route. Halts further execution in the current action. Raises RouterError if a given named route isn’t found in the app’s routes.
reroute MyController, :action
#=> Executes MyController#action
reroute MyController, :show, :id => 123
#=> Executes MyController#action with the given params merged to
#=> the current params.
reroute :show_foo
#=> Executes the current controller's :show_foo action, or if missing
#=> the controller and action for the :show_foo named route.
# Reroute with the given headers.
reroute :show_foo, {}, 'HTTP_X_CUSTOM_HEADER' => 'foo'
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 |
# File 'lib/gin/controller.rb', line 628 def reroute *args args.unshift(self.class) if Symbol === args[0] && self.class.actions.include?(args[0]) nheaders = args.pop if Hash === args.last && Hash === args[-2] && args[-2] != args[-1] nparams = args.pop if Hash === args.last if Class === args[0] ctrl_klass, naction = args[0..1] else route = @app.router.route_to(*args) ctrl_klass, naction = route.target end nenv = @env.merge(nheaders || {}) nenv[GIN_PATH_PARAMS] = {} ctrl = ctrl_klass.new(@app, nenv) ctrl.params.merge!(params) ctrl.params.merge!(nparams) if nparams halt(*ctrl.call_action(naction)) end |
#rewrite(*args) ⇒ Object
Halt execution of the current controller action and create a new request to another action and/or controller, or path.
Raises Gin::RouterError if the controller and action don’t have a route. Returns a 404 response if an unrecognized path is given.
The rewrite method acts just as if a request had been sent from the client, and will re-run any of the in-app middleware. If the app is itself running as middleware, you may use rewrite to pass a request down to the next item in the stack by specifying a path not supported by the app.
Supports the same arguments at the Gin::Controller#url_to method.
rewrite MyController, :action
#=> Calls app with route for MyController#action
rewrite MyController, :show, :id => 123
#=> Calls app with route for MyController#action with the given params
rewrite :show_foo
#=> Calls app with route for the current controller's :show_foo action,
#=> or if missing the controller and action for the :show_foo named route.
# Rewrite and execute the request with the given headers.
rewrite :show_foo, 'HTTP_X_CUSTOM_HEADER' => 'foo'
rewrite :show_foo, params, 'HTTP_X_CUSTOM_HEADER' => 'foo'
# Rewrite to an arbitrary path.
rewrite '/path/to/something/else', {}, 'REQUEST_METHOD' => 'POST'
Note that params are not forwarded with the rewrite call. The app considers this to be a completely different request, which means all params required must be passed explicitely.
Streamed and IO request content is also ignored unless it is explicitely assigned to the ‘rack.input’ (as a part of the headers argument).
601 602 603 604 605 |
# File 'lib/gin/controller.rb', line 601 def rewrite *args args.unshift(self.class) if Symbol === args[0] && self.class.actions.include?(args[0]) halt(*@app.rewrite!(@env, *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.
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 |
# File 'lib/gin/controller.rb', line 656 def send_file path, opts={} if opts[:type] || !@response[CNT_TYPE] 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[CNT_DISPOSITION] = "%s; filename=\"%s\"" % [disposition, filename] end last_modified opts[:last_modified] || File.mtime(path).httpdate halt 200 if @request.head? @response[CNT_LENGTH] = File.size?(path).to_s halt 200, File.open(path, "rb") rescue Errno::ENOENT halt 404 end |
#session ⇒ Object
Access the request session.
437 438 439 |
# File 'lib/gin/controller.rb', line 437 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
456 457 458 459 460 461 462 463 464 |
# File 'lib/gin/controller.rb', line 456 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.
268 269 270 271 |
# File 'lib/gin/controller.rb', line 268 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
412 413 414 415 |
# File 'lib/gin/controller.rb', line 412 def stream keep_open=false, &block scheduler = env[ASYNC_CALLBACK] ? EventMachine : Gin::Stream body Gin::Stream.new(scheduler, keep_open){ |out| yield(out) } end |
#template_path(template, is_layout = false) ⇒ Object
Returns the path to where the template is expected to be.
template_path :foo
#=> "<views_dir>/foo"
template_path "sub/foo"
#=> "<views_dir>/sub/foo"
template_path "sub/foo", :layout
#=> "<layouts_dir>/sub/foo"
template_path "/other/foo"
#=> "<root_dir>/other/foo"
848 849 850 851 852 853 854 855 856 857 858 859 860 |
# File 'lib/gin/controller.rb', line 848 def template_path template, is_layout=false dir = if template.to_s[0] == ?/ @app.root_dir elsif is_layout @app.layouts_dir else @app.views_dir end path = File.join(dir, template.to_s) path.gsub!('*', controller_name) File.(path) end |
#url_to(*args) ⇒ Object Also known as: to
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 |
# File 'lib/gin/controller.rb', line 520 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 |
#view(template, opts = {}, &block) ⇒ Object
Render a template with the given view template. Options supported:
- :locals
-
Hash - local variables used in template
- :layout
-
Symbol/String - a custom layout to use
- :scope
-
Object - The scope in which to render the template: default self
- :content_type
-
Symbol/String - Content-Type header to set
- :engine
-
String - Tilt rendering engine to use
- :layout_engine
-
String - Tilt layout rendering engine to use
The template argument may be a String or a Symbol. By default the template location will be looked for under Gin::App.views_dir, but the directory may be specified as any directory under Gin::App.root_dir by using the ‘/’ prefix:
view 'foo/template'
#=> Renders file "<views_dir>/foo/template"
view '/foo/template'
#=> Renders file "<root_dir>/foo/template"
# Render without layout
view 'foo/template', layout: false
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
# File 'lib/gin/controller.rb', line 887 def view template, opts={}, &block content_type(opts.delete(:content_type)) if opts[:content_type] scope = opts[:scope] || self locals = opts[:locals] || {} template = template_path(template) v_template = @app.template_for template, opts[:engine] raise Gin::TemplateMissing, "No such template `#{template}'" unless v_template if opts[:layout] != false r_layout = template_path((opts[:layout] || layout), true) r_template = @app.template_for r_layout, opts[:layout_engine] if r_layout end if !@response[CNT_TYPE] mime_type = v_template.class.default_mime_type || r_template && r_template.class.default_mime_type content_type(mime_type) if mime_type end @env[GIN_TEMPLATES] ||= [] if r_template @env[GIN_TEMPLATES] << r_template.file << v_template.file r_template.render(scope, locals){ v_template.render(scope, locals, &block) } else @env[GIN_TEMPLATES] << v_template.file v_template.render(scope, locals, &block) end end |