Class: ActionController::Routing::RouteSet

Inherits:
Object
  • Object
show all
Defined in:
lib/action_controller/routing.rb

Overview

:nodoc:

Defined Under Namespace

Classes: Mapper, NamedRouteCollection

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRouteSet

Returns a new instance of RouteSet.



1115
1116
1117
1118
# File 'lib/action_controller/routing.rb', line 1115

def initialize
  self.routes = []
  self.named_routes = NamedRouteCollection.new
end

Instance Attribute Details

#named_routesObject

Returns the value of attribute named_routes.



1113
1114
1115
# File 'lib/action_controller/routing.rb', line 1113

def named_routes
  @named_routes
end

#routesObject

Returns the value of attribute routes.



1113
1114
1115
# File 'lib/action_controller/routing.rb', line 1113

def routes
  @routes
end

Instance Method Details

#add_named_route(name, path, options = {}) ⇒ Object



1166
1167
1168
# File 'lib/action_controller/routing.rb', line 1166

def add_named_route(name, path, options = {})
  named_routes[name] = add_route(path, options)
end

#add_route(path, options = {}) ⇒ Object



1160
1161
1162
1163
1164
# File 'lib/action_controller/routing.rb', line 1160

def add_route(path, options = {})
  route = builder.build(path, options)
  routes << route
  route
end

#build_expiry(options, recall) ⇒ Object



1189
1190
1191
1192
1193
1194
# File 'lib/action_controller/routing.rb', line 1189

def build_expiry(options, recall)
  recall.inject({}) do |expiry, (key, recalled_value)|
    expiry[key] = (options.key?(key) && options[key] != recalled_value)
    expiry
  end
end

#builderObject

Subclasses and plugins may override this method to specify a different RouteBuilder instance, so that other route DSL’s can be created.



1122
1123
1124
# File 'lib/action_controller/routing.rb', line 1122

def builder
  @builder ||= RouteBuilder.new
end

#clear!Object



1132
1133
1134
1135
1136
1137
# File 'lib/action_controller/routing.rb', line 1132

def clear!
  routes.clear
  named_routes.clear
  @combined_regexp = nil
  @routes_by_controller = nil
end

#draw {|Mapper.new(self)| ... } ⇒ Object

Yields:



1126
1127
1128
1129
1130
# File 'lib/action_controller/routing.rb', line 1126

def draw
  clear!
  yield Mapper.new(self)
  named_routes.install
end

#empty?Boolean

Returns:

  • (Boolean)


1139
1140
1141
# File 'lib/action_controller/routing.rb', line 1139

def empty?
  routes.empty?
end

#extra_keys(options, recall = {}) ⇒ Object

Generate the path indicated by the arguments, and return an array of the keys that were not used to generate it.



1198
1199
1200
# File 'lib/action_controller/routing.rb', line 1198

def extra_keys(options, recall={})
  generate_extras(options, recall).last
end

#extract_request_environment(request) ⇒ Object

Subclasses and plugins may override this method to extract further attributes from the request, for use by route conditions and such.



1306
1307
1308
# File 'lib/action_controller/routing.rb', line 1306

def extract_request_environment(request)
  { :method => request.method }
end

#generate(options, recall = {}, method = :generate) ⇒ Object

Raises:



1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
# File 'lib/action_controller/routing.rb', line 1206

def generate(options, recall = {}, method=:generate)
  named_route_name = options.delete(:use_route)
  if named_route_name
    named_route = named_routes[named_route_name]
    options = named_route.parameter_shell.merge(options)
  end

  options = options_as_params(options)
  expire_on = build_expiry(options, recall)

  # if the controller has changed, make sure it changes relative to the
  # current controller module, if any. In other words, if we're currently
  # on admin/get, and the new controller is 'set', the new controller
  # should really be admin/set.
  if !named_route && expire_on[:controller] && options[:controller] && options[:controller][0] != ?/
    old_parts = recall[:controller].split('/')
    new_parts = options[:controller].split('/')
    parts = old_parts[0..-(new_parts.length + 1)] + new_parts
    options[:controller] = parts.join('/')
  end

  # drop the leading '/' on the controller name
  options[:controller] = options[:controller][1..-1] if options[:controller] && options[:controller][0] == ?/
  merged = recall.merge(options)
    
  if named_route
    path = named_route.generate(options, merged, expire_on)
    raise RoutingError, "#{named_route_name}_url failed to generate from #{options.inspect}, expected: #{named_route.requirements.inspect}, diff: #{named_route.requirements.diff(options).inspect}" if path.nil?
    return path
  else
    merged[:action] ||= 'index'
    options[:action] ||= 'index'
  
    controller = merged[:controller]
    action = merged[:action]

    raise RoutingError, "Need controller and action!" unless controller && action
    # don't use the recalled keys when determining which routes to check
    routes = routes_by_controller[controller][action][options.keys.sort_by { |x| x.object_id }]

    routes.each do |route|
      results = route.send(method, options, merged, expire_on)
      return results if results && (!results.is_a?(Array) || results.first)
    end
  end
    
  raise RoutingError, "No route matches #{options.inspect}"
end

#generate_extras(options, recall = {}) ⇒ Object



1202
1203
1204
# File 'lib/action_controller/routing.rb', line 1202

def generate_extras(options, recall={})
  generate(options, recall, :generate_extras)
end

#load!Object Also known as: reload



1143
1144
1145
1146
1147
1148
# File 'lib/action_controller/routing.rb', line 1143

def load!
  Routing.use_controllers! nil # Clear the controller cache so we may discover new ones
  clear!
  load_routes!
  named_routes.install
end

#load_routes!Object



1152
1153
1154
1155
1156
1157
1158
# File 'lib/action_controller/routing.rb', line 1152

def load_routes!
  if defined?(RAILS_ROOT) && defined?(::ActionController::Routing::Routes) && self == ::ActionController::Routing::Routes
    load File.join("#{RAILS_ROOT}/config/routes.rb")
  else
    add_route ":controller/:action/:id"
  end
end

#options_as_params(options) ⇒ Object



1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
# File 'lib/action_controller/routing.rb', line 1170

def options_as_params(options)
  # If an explicit :controller was given, always make :action explicit
  # too, so that action expiry works as expected for things like
  #
  #   generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
  #
  # (the above is from the unit tests). In the above case, because the
  # controller was explicitly given, but no action, the action is implied to
  # be "index", not the recalled action of "show".
  #
  # great fun, eh?

  options_as_params = options[:controller] ? { :action => "index" } : {}
  options.each do |k, value|
    options_as_params[k] = value.to_param
  end
  options_as_params
end

#recognize(request) ⇒ Object



1255
1256
1257
1258
1259
# File 'lib/action_controller/routing.rb', line 1255

def recognize(request)
  params = recognize_path(request.path, extract_request_environment(request))
  request.path_parameters = params.with_indifferent_access
  "#{params[:controller].camelize}Controller".constantize
end

#recognize_path(path, environment = {}) ⇒ Object

Raises:



1261
1262
1263
1264
1265
1266
1267
# File 'lib/action_controller/routing.rb', line 1261

def recognize_path(path, environment={})
  path = CGI.unescape(path)
  routes.each do |route|
    result = route.recognize(path, environment) and return result
  end
  raise RoutingError, "no route found to match #{path.inspect} with #{environment.inspect}"
end

#routes_by_controllerObject



1269
1270
1271
1272
1273
1274
1275
1276
1277
# File 'lib/action_controller/routing.rb', line 1269

def routes_by_controller
  @routes_by_controller ||= Hash.new do |controller_hash, controller|
    controller_hash[controller] = Hash.new do |action_hash, action|
      action_hash[action] = Hash.new do |key_hash, keys|
        key_hash[keys] = routes_for_controller_and_action_and_keys(controller, action, keys)
      end
    end
  end
end

#routes_for(options, merged, expire_on) ⇒ Object



1279
1280
1281
1282
1283
1284
1285
1286
# File 'lib/action_controller/routing.rb', line 1279

def routes_for(options, merged, expire_on)
  raise "Need controller and action!" unless controller && action
  controller = merged[:controller]
  merged = options if expire_on[:controller]
  action = merged[:action] || 'index'
    
  routes_by_controller[controller][action][merged.keys]
end

#routes_for_controller_and_action(controller, action) ⇒ Object



1288
1289
1290
1291
1292
1293
# File 'lib/action_controller/routing.rb', line 1288

def routes_for_controller_and_action(controller, action)
  selected = routes.select do |route|
    route.matches_controller_and_action? controller, action
  end
  (selected.length == routes.length) ? routes : selected
end

#routes_for_controller_and_action_and_keys(controller, action, keys) ⇒ Object



1295
1296
1297
1298
1299
1300
1301
1302
# File 'lib/action_controller/routing.rb', line 1295

def routes_for_controller_and_action_and_keys(controller, action, keys)
  selected = routes.select do |route|
    route.matches_controller_and_action? controller, action
  end
  selected.sort_by do |route|
    (keys - route.significant_keys).length
  end
end