Giter VIP home page Giter VIP logo

namespaced-routes-reading's Introduction

Namespaced Routes

Objectives

  1. Understand the use of scope and namespace in routes.rb.
  2. Create a module scoped controller.

Lesson

We're going to explore different ways of routing things in our blog application to help us organize and group certain routes and controllers more logically.

Blog Stats

We decide that we want to keep track of some basic blog statistics, such as how many posts and authors we have. We start by creating a stats_controller.rb with an index action and corresponding view.

We can't actually browse to it yet because we need to set up a route. Let's add it to routes.rb:

# config/routes.rb

get '/stats', to: 'stats#index'

Easy enough, but, after thinking about it, /stats isn't something we want to just hang off the root of our blog URL for anyone to see. It's really just for blog admins, and we want to set up a URL scheme to segregate admin things into their own logical space.

We modify our route:

# config/routes.rb

get '/admin/stats', to: 'stats#index'

Now we can browse to /admin/stats for the stats page, and we can no longer go straight to /stats.

Scoping Routes

Over time, we might decide to add more admin functions, grouping them all together like we did above, until eventually our routes.rb looks something like this:

# config/routes.rb

...

get '/admin/stats', to: 'stats#index'
get '/admin/authors/new', to: 'authors#new'
get '/admin/authors/delete', to: 'authors#delete'
get '/admin/authors/create', to: 'authors#create'
get '/admin/comments/moderate', to: 'comments#moderate'

As you can see, even with only a few more actions in our admin section, our routes are getting ugly. Not to mention we're repeating ourselves a lot by typing in /admin on all these routes. Yes, even routes should be DRY!

What we need is a way to group all these under /admin without typing /admin all the time. That's where scope comes in.

In routing, scope allows us to prefix a block of routes under one grouping. So let's change our stats route:

# config\routes.rb

scope '/admin' do
  resources :stats, only: [:index]
end

Now we can reload /admin/stats, and it still works. Notice our new route is resourced. Now that we don't have to manually prefix /admin, we can go back to using resourced routes within the /admin scope.

If you run rake routes, you'll see that the new /admin/stats helpers are stats_path and stats_url.

Scoping With Modules

Scoping works nicely to group our URLs together logically, but what happens when we have a bunch of controllers that are handling admin functions? As the application grows, it's going to be harder and harder to keep track of which controllers are for regular blog functions and which are for admin functions.

We want to group all our admin controllers logically to make it easier to maintain and add to the app, so let's add an /admin directory under /controllers where all the admin controllers will go:

mkdir app/controllers/admin

Now let's move our stats_controller.rb into the /admin folder:

mv app/controllers/stats_controller.rb app/controllers/admin

When you create a new folder under /controllers, Rails will automatically pick that up as a module and expect you to namespace the controller accordingly. We need to modify our admin/stats_controller.rb to look like this:

# controllers/admin/stats_controller.rb

class Admin::StatsController < ApplicationController
  def index

    ...

  end
end

Now that we have our controller in a module, Rails will expect the views to match. Let's create a new directory at /app/views/admin/stats and move our stats/index.html.erb into it, so we'll wind up with /app/views/admin/stats/index.html.erb.

Top-tip: The views folder for a controller module (in this case /admin) expects a subfolder structure that matches the names of the controllers (in this case /admin/stats).

If we try to reload /admin/stats now, we will get an error because we need to tell our routes about our new module.

# config/routes.rb

scope '/admin', module: 'admin' do
  resources :stats, only: [:index]
end

We're telling scope that we want to use /admin as a URL prefix, and we're also letting Rails know that all of the included routes will be handled by controllers in the admin module.

If we reload /admin/stats, everything should work just like it did, but now we are logically organizing our controllers.

Namespace

Right now, our route is scoped as scope '/admin', module: 'admin', which is fine but perhaps a bit less DRY than we'd like.

Fortunately, Rails gives us a shortcut here. When we want to route with a module and use that module's name as the URL prefix, we can use the namespace method instead of scope, module.

# config/routes.rb

namespace :admin do
  resources :stats, only: [:index]
end

If we reload /admin/stats, everything still works, but we've simplified the declaration of the routes. The namespace method makes the assumption that the path prefix and module name match, saving us some typing.

Top-tip: There is one important difference between scope '/admin', module: 'admin' and namespace :admin, and it's in the URL helpers. Remember above that using scope gave us a stats_path helper. But now that we are using namespace, run rake routes again. You'll see that the helper is now prefixed with admin_, so stats_path becomes admin_stats_path. If you switch from scope to namespace, take care to update any URL helpers you have in use!

Summary

We learned how to organize our URLs by using scope to group them with an /admin prefix; how to further organize our controllers using directories and modules; and how to use scope, module or namespace in our routes.

namespaced-routes-reading's People

Contributors

annjohn avatar bhollan avatar blake41 avatar franknowinski avatar ihollander avatar jmburges avatar jo-hooton avatar maxwellbenton avatar scottcreynolds avatar sdcrouse avatar zachnewburgh avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

namespaced-routes-reading's Issues

NameError: uninitialized constant

Rspec throws an error once you move StatsController to the controllers/admin directory. Both spec/controller/stats_controller_spec.rb and spec/controller/stats_helper_spec.rb complain about uninitialized constant(s). It obviously works again once you manually delete or comment out those two files. Perhaps deleting them from the repo would be easier?

chat

I cant type a response in the ask a question chat.

Reading Lesson setup as a Lab Lesson

This lesson is a reading but it is set up as if it is a lab. If you run learn, it tests for 6 test...none of which are part of what is being done in the reading.

Error while running bundle install/learn open

/ ♥ learn open
Looking for lesson...
Forking lesson...
Cloning lesson...
Opening lesson...
Bundling...
Fetching gem metadata from https://rubygems.org/.............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Bundler could not find compatible versions for gem "bundler":
In Gemfile:
rails (~> 4.2) was resolved to 4.2.11.1, which depends on
bundler (>= 1.3.0, < 2.0)

Current Bundler version:
bundler (2.0.1)
This Gemfile requires a different version of Bundler.
Perhaps you need to update Bundler by running gem install bundler?

Could not find gem 'bundler (>= 1.3.0, < 2.0)', which is required by gem 'rails
(~> 4.2)', in any of the sources.

Bundler could not find compatible versions for gem "ruby":
In Gemfile:
ruby

capybara was resolved to 3.21.0, which depends on
  ruby (>= 2.4.0)

rails (~> 4.2) was resolved to 4.2.11.1, which depends on
  ruby (>= 1.9.3)

Done.

Installing an earlier version of bunlder, 1.9.9, and running bundle install clears the rails gem dependencies but im also hitting an error for ruby now in

[14:27:07] (master) namespaced-routes-reading-online-web-ft-031119
// ♥ gem install bundler -v 1.9.9
Fetching bundler-1.9.9.gem
Successfully installed bundler-1.9.9
Parsing documentation for bundler-1.9.9
Installing ri documentation for bundler-1.9.9
Done installing documentation for bundler after 1 seconds
1 gem installed
[14:28:14] (master) namespaced-routes-reading-online-web-ft-031119
// ♥ bundle 1.9.9 install
Fetching gem metadata from https://rubygems.org/..............
Fetching version metadata from https://rubygems.org/...
Fetching dependency metadata from https://rubygems.org/..
Resolving dependencies..............
Using rake 12.3.2
Using concurrent-ruby 1.1.5
Using i18n 0.9.5
Using minitest 5.11.3
Using thread_safe 0.3.6
Using tzinfo 1.2.5
Using activesupport 4.2.11.1
Using builder 3.2.3
Using erubis 2.7.0
Using mini_portile2 2.4.0
Using nokogiri 1.10.3
Using rails-deprecated_sanitizer 1.0.3
Using rails-dom-testing 1.0.9
Using crass 1.0.4
Using loofah 2.2.3
Using rails-html-sanitizer 1.0.4
Using actionview 4.2.11.1
Using rack 1.6.11
Using rack-test 0.6.3
Using actionpack 4.2.11.1
Using globalid 0.4.2
Using activejob 4.2.11.1
Using mini_mime 1.0.1
Using mail 2.7.1
Using actionmailer 4.2.11.1
Using activemodel 4.2.11.1
Using arel 6.0.4
Using activerecord 4.2.11.1
Using public_suffix 3.1.0
Using addressable 2.6.0
Using debug_inspector 0.0.3
Using binding_of_caller 0.8.0
Using bundler 1.9.9
Using byebug 11.0.1
Using regexp_parser 1.5.1
Using xpath 3.2.0

Gem::RuntimeRequirementNotMetError: capybara requires Ruby version >= 2.4.0. The current ruby version is 2.3.7.456.
An error occurred while installing capybara (3.21.0), and Bundler cannot
continue.
Make sure that gem install capybara -v '3.21.0' succeeds before bundling.

At this point im not sure what i need to do to get this lab running without potentially causing more issues. Will report if i find a solution.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.