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.
-
.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
Instance Attribute Details
#action ⇒ Object (readonly)
The action that the HTTP request resolved to, based on the App’s router.
194 195 196 |
# File 'lib/gin/controller.rb', line 194 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.
185 186 187 |
# File 'lib/gin/controller.rb', line 185 def app @app end |
#env ⇒ Object (readonly)
The Rack env hash.
197 198 199 |
# File 'lib/gin/controller.rb', line 197 def env @env end |
#request ⇒ Object (readonly)
Gin::Request instance representing the HTTP request.
188 189 190 |
# File 'lib/gin/controller.rb', line 188 def request @request end |
#response ⇒ Object (readonly)
Gin::Response instance representing the HTTP response.
191 192 193 |
# File 'lib/gin/controller.rb', line 191 def response @response end |
Class Method Details
.actions ⇒ Object
Array of action names for this controller.
87 88 89 |
# File 'lib/gin/controller.rb', line 87 def self.actions instance_methods(false).map{|a| a.to_sym } 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’.
161 162 163 164 165 |
# File 'lib/gin/controller.rb', line 161 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.
137 138 139 140 141 142 |
# File 'lib/gin/controller.rb', line 137 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.
101 102 103 104 |
# File 'lib/gin/controller.rb', line 101 def self.controller_name new_name=nil @ctrl_name = new_name if new_name @ctrl_name end |
.default_route_for(action) ⇒ Object
:nodoc:
118 119 120 |
# File 'lib/gin/controller.rb', line 118 def self.default_route_for action #:nodoc: DEFAULT_ACTION_MAP[action] || ['GET', "/#{action}"] end |
.display_name(action = nil) ⇒ Object
:nodoc:
128 129 130 |
# File 'lib/gin/controller.rb', line 128 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.
149 150 151 152 153 |
# File 'lib/gin/controller.rb', line 149 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 |
# File 'lib/gin/controller.rb', line 70 def self.inherited subclass subclass.setup 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.
174 175 176 177 178 |
# File 'lib/gin/controller.rb', line 174 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:
123 124 125 |
# File 'lib/gin/controller.rb', line 123 def self.route_name_for action #:nodoc: "#{action}_#{controller_name.sub(%r{^.*/},'')}".to_sym end |
.setup ⇒ Object
:nodoc:
76 77 78 79 |
# File 'lib/gin/controller.rb', line 76 def self.setup # :nodoc: @layout = nil @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.
776 777 778 |
# File 'lib/gin/controller.rb', line 776 def asset path @app.asset path end |
#asset_path(name) ⇒ Object
Returns the HTTP path to the local asset.
756 757 758 759 760 761 762 763 764 765 766 767 768 769 |
# File 'lib/gin/controller.rb', line 756 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.
746 747 748 749 750 |
# File 'lib/gin/controller.rb', line 746 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.
233 234 235 236 |
# File 'lib/gin/controller.rb', line 233 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
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 |
# File 'lib/gin/controller.rb', line 686 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.
212 213 214 215 216 217 218 |
# File 'lib/gin/controller.rb', line 212 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.
242 243 244 |
# File 'lib/gin/controller.rb', line 242 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'
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/gin/controller.rb', line 261 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.
401 402 403 |
# File 'lib/gin/controller.rb', line 401 def @request. end |
#delete_cookie(name) ⇒ Object
Delete the response cookie with the given name. Does not affect request cookies.
427 428 429 |
# File 'lib/gin/controller.rb', line 427 def name @response. name end |
#dispatch(action) ⇒ Object
Dispatch the call to the action, calling before and after filers, and including error handling.
901 902 903 904 905 906 907 908 909 910 911 912 913 914 |
# File 'lib/gin/controller.rb', line 901 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.
307 308 309 310 311 |
# File 'lib/gin/controller.rb', line 307 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.
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/gin/controller.rb', line 319 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:
344 345 346 347 |
# File 'lib/gin/controller.rb', line 344 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.
737 738 739 740 |
# File 'lib/gin/controller.rb', line 737 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
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 |
# File 'lib/gin/controller.rb', line 715 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.
954 955 956 |
# File 'lib/gin/controller.rb', line 954 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"
293 294 295 296 297 298 299 300 301 |
# File 'lib/gin/controller.rb', line 293 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.
353 354 355 356 |
# File 'lib/gin/controller.rb', line 353 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.
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 |
# File 'lib/gin/controller.rb', line 925 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.
882 883 884 885 886 887 888 889 890 891 892 893 894 |
# File 'lib/gin/controller.rb', line 882 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.
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 |
# File 'lib/gin/controller.rb', line 644 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.
785 786 787 |
# File 'lib/gin/controller.rb', line 785 def layout self.class.layout || @app.layout end |
#logger ⇒ Object
Accessor for main application logger.
377 378 379 |
# File 'lib/gin/controller.rb', line 377 def logger @app.logger end |
#mime_type(type) ⇒ Object
Get the normalized mime-type matching the given input.
250 251 252 |
# File 'lib/gin/controller.rb', line 250 def mime_type type @app.mime_type type end |
#params ⇒ Object
Get the request params.
385 386 387 |
# File 'lib/gin/controller.rb', line 385 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"
449 450 451 452 453 454 |
# File 'lib/gin/controller.rb', line 449 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)
507 508 509 510 511 512 513 514 515 516 |
# File 'lib/gin/controller.rb', line 507 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'
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
# File 'lib/gin/controller.rb', line 584 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).
557 558 559 560 561 |
# File 'lib/gin/controller.rb', line 557 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.
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 |
# File 'lib/gin/controller.rb', line 612 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.
393 394 395 |
# File 'lib/gin/controller.rb', line 393 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
412 413 414 415 416 417 418 419 420 |
# File 'lib/gin/controller.rb', line 412 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.
224 225 226 227 |
# File 'lib/gin/controller.rb', line 224 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
368 369 370 371 |
# File 'lib/gin/controller.rb', line 368 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"
804 805 806 807 808 809 810 811 812 813 814 815 816 |
# File 'lib/gin/controller.rb', line 804 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
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
# File 'lib/gin/controller.rb', line 476 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
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 |
# File 'lib/gin/controller.rb', line 843 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 |