Class: Ink::Controller

Inherits:
Object
  • Object
show all
Defined in:
lib/webink/controller.rb

Overview

Controller class

Usage

Controllers handle incoming requests and decide what to do with them. A controller has access to all incoming data, like POST and GET (through @params and @params as well as the config.

class App < Ink::Controller

  def index
    redirect_to :controller => "my_app", :module => "feed",
      :id => 29382374
  end

  def feed
    @arg = @params[:id]
    @users = []
    render :template => "index"
  end

  def partial
    @arg = "foo bar"
    render :partial => "part", :standalone => true
  end

end

A controller named App should have the filename app.rb and be placed inside the project controllers folder. It can have instance methods that are usually refered to as modules. So a route should contain at least a :controller and a :module. Note that controller filenames are not camelized when they are being searched for by the dispatcher.

In the sample above there are three modules, index redirects to feed, feed renders a template and partial renders a partial. When using a partial inside a template, you do not need the standalone argument, but when you plan to return just the partial, you should add it to the argument string. Rendering returns an interpreted erb instance, which is returned to the calling part of the script, which runs the erb instance. Redirecting forwards an erb instance and passes on the existing @params, after overwriting and setting its hash arguments, so multiple redirecting works.

The template is called inside the binding on the controller, which means that all instance variables and methods are available as such.

Templates

All templates are to be put into the project views folder, and are to be named name.html.erb, while partials are to be named _anothername.html.erb. It is possible to create subfolders and call the templates via :template => “subfolder/template.html.erb”.

The index.html.erb template in the controller above looks like this:

<%= render :partial => "part" %>

And the _part.html.erb, that is called from the index, is this:

WTF <%= @arg %>!!
<br>

When the index module is requested, it will set :id to 29382374. However requesting the feed module, it requires :id to be set as a parameter through the routes.

Routing

The routes being evaluated by the dispatcher are simple regular expressions. This example fits the controller from earlier.

Beauty.root = "/folder"

Beauty.routes = [
  [ /^\/([^\/]+)\/([^\/]+)(\/([0-9]+))?$/,
    {:controller => "$1", :module => "$2", :id => "$4"} ],
  [ /^\/([^\/]+)\/?$/, {:controller => "$1", :module => "index"} ],
  [ /^\/?$/, {:controller => "app", :module => "index"} ],
]

Routes are built as a priority list, the first match will be the route taken. All route configurations must include a variable named root, as it will help to create dynamic links within websites. Root is relative to the webserver root. Assume your webserver points to public_html, then routes can be “” for the public_html folder, or “/anysubfolder” which points to anysubfolder. Deeper structures work too.

Linking

A controller has the ability to create hyperlinks for you, that will dynamically match the project path etc. (and is also using the root variable from the routes.rb)

link_to "name", "controller", "module", "param1", "param2",
  {:class => "h1", :id => "14"}

The link above will produce this:

<a class="h1" id="14" href="/controller/module/param1/param2/">name</a>

So the first entry of the argument array is the hyperlink name, then all following entries are connected as the href string, prefixed by the root variable that is set in the routes.rb. The hash includes the attributes for the <a>-tag.

Pathing

A controller also constructs paths for you (and is also using the root variable from the routes.rb), which you can use to dynamically reroute forms, just to mention one example.

@my = "no"
path_to "this", "is", @my, "path"

The constructed path will look like this:

/this/is/no/path

It just puts together the arguments given to it.

Sessions

Usually very important in the development of websites are sessions. There is some basic support for it in webink, that will make certain bits easier. For more information have a look at the blog-demo.

Each controller usually expects cookies to work. Whenever cookies do not work, or you do not intend to use them in the first place, path_to and link_to watch out for the instance variables @session_key and @session_id which are added via GET to the path/hyperlink, that they construct. Therefore the tools should not be used for external linking. The dispatcher automatically filters the GET session_id when using POST and adds it to the cgi.params, so sessions can be used confortably.

Per default, the @session_key should be “_session_id”, but the controller offers some freedom, in case you may want a different key name for some reason.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params) ⇒ Controller

Constructor

Creates a new controller of the derived class. params are the globals set by the dispatcher, and include keys like: :get, :post and :config. Also the matched routes are put there, :controller, :module and any parameters like :id or :page that were retrieved from the routes.

param params:

Hash of Symbol => Objects



158
159
160
# File 'lib/webink/controller.rb', line 158

def initialize(params)
  @params = params
end

Class Method Details

.verify(controller) ⇒ Object

Class method

Retrieve the class of the name controller, that can be instanciated by using new. Raises a NameError.

param controller:

Controller name string

returns:

class or nil



285
286
287
288
289
290
291
292
293
294
295
# File 'lib/webink/controller.rb', line 285

def self.verify(controller)
  if not Module.const_defined?(controller.capitalize)
    if File.exists? "./controllers/#{controller}.rb" and
        Module.const_get(controller.capitalize).is_a?(Class)
      load "./controllers/#{controller}.rb"
    else
      raise NameError.new("Controller not found.")
    end
  end
  Module.const_get(controller.capitalize)
end

Instance Method Details

#getBinding(locals) ⇒ Object

Instance method

Retrieve the current binding of the instance.

param locals:

an Array of data for the template

returns:

current binding



275
276
277
# File 'lib/webink/controller.rb', line 275

def getBinding(locals)
  binding
end

Instance method

Creates a dynamic hyperlink First argument is the name, then follow the pieces that are imploded by a /, followed by hashes, that become attributes. It adds the @session_key and @session_id if they are set. Convenience method

param args:

Array of Strings and Hashes

returns:

Hyperlink



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/webink/controller.rb', line 226

def link_to(*args)
  if not args.instance_of? Array and args.length < 2
    raise ArgumentError.new("Expects an array.")
  end
  href = "#{@params[:root]}/"
  a = "<a "
  name = args[0]
  for i in 1...args.length
    arg = args[i]
    if not arg.instance_of? Hash
      href += "#{arg}/"
    else
      arg.each do |k,v|
        a += "#{k}=\"#{v}\" "
      end
    end
  end
  href += "?#{@session_key}=#{@session_id}" if @session_id and @session_key
  "#{a}href=\"#{href}\">#{name}</a>"
end

#path_to(*args) ⇒ Object

Instance method

Creates a dynamic path The array pieces are imploded by a /. It adds the @session_key and @session_id if they are set. Convenience method

param args:

Array of Strings or String

returns:

path



255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/webink/controller.rb', line 255

def path_to(*args)
  href = "#{@params[:root]}/"

  if args.is_a? Array
    for i in 0...args.length
      arg = args[i]
      href += "#{arg}/"
    end
  else
    href += "#{args}/"
  end
  href += "?#{@session_key}=#{@session_id}" if @session_id and @session_key
  href
end

#redirect_to(args) ⇒ Object

Instance method

Redirect to a controller and module. The new controller will be instanciated with a copy of the current params.

param args:

Hash of arguments

returns:

interpreted erb instance or nil



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/webink/controller.rb', line 201

def redirect_to(args)
  p = Hash.new
  @params.each do |k,v|
    p[k] = v
  end
  args.each do |k,v|
    p[k] = v
  end
  if p[:controller] and p[:module]
    controller = Ink::Controller.verify(p[:controller]).new(p)
    controller.verify(p[:module]).call
  else
    nil
  end
end

#render(args) ⇒ Object

Instance method

Render a template or a partial that is located in the ./views/ folder of the project. Subfolders are allowed to be specified. All instance variables are accessible from within the template, as are any instance methods.

param args:

Hash of arguments

returns:

interpreted erb instance or nil



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/webink/controller.rb', line 170

def render(args)
  args[:locals] = Array.new if not args[:locals]
  template = nil
  if args[:template]
    template = File.open "./views/#{args[:template]}.html.erb", "r"
    erb = ERB.new template.readlines * "\n"
    template.close
    [200, @params[:header], erb.result(self.getBinding(args[:locals]))]
  elsif args[:partial]
    template = File.open "./views/#{
      (File.dirname(args[:partial]) != ".") ?
        "#{File.dirname(args[:partial])}/" : ""
      }_#{File.basename(args[:partial])}.html.erb", "r"
    erb = ERB.new template.readlines * "\n"
    template.close
    if not args[:standalone]
      erb.result(self.getBinding(args[:locals]))
    else
      [200, @params[:header], erb.result(self.getBinding(args[:locals]))]
    end
  else
    nil
  end
end

#verify(mod) ⇒ Object

Instance method

Retrieve the method of name mod, that can be called by using the call method. Raises a NameError.

param mod:

Method name string

returns:

method or nil



303
304
305
# File 'lib/webink/controller.rb', line 303

def verify(mod)
  self.method(mod)
end