From d1926fb0d7b705dc7b8838017214e1bdf67ed609 Mon Sep 17 00:00:00 2001 From: Mike Simkins Date: Thu, 2 Sep 2010 16:37:46 +0100 Subject: [PATCH] Started to Implement D-A, and roles scaffold - Need to finish Test Suite --- Gemfile | 3 +- Gemfile.lock | 22 ++-- app/controllers/application_controller.rb | 5 - app/controllers/roles_controller.rb | 83 ++++++++++++++ app/helpers/roles_helper.rb | 2 + app/models/assignment.rb | 4 + app/models/role.rb | 4 +- app/models/user.rb | 9 +- app/views/roles/_form.html.erb | 21 ++++ app/views/roles/edit.html.erb | 6 + app/views/roles/index.html.erb | 23 ++++ app/views/roles/new.html.erb | 5 + app/views/roles/show.html.erb | 10 ++ config/routes.rb | 2 + ...01125550_users_have_and_belong_to_many_roles.rb | 11 -- ...migration.rb => 20100902151516_create_roles.rb} | 3 +- db/migrate/20100902151904_create_assignments.rb | 14 +++ .../20100902153434_generate_initial_roles.rb | 8 ++ db/schema.rb | 14 ++- features/manage_roles.feature | 47 ++++++++ features/step_definitions/role_steps.rb | 14 +++ features/support/paths.rb | 3 + spec/controllers/roles_controller_spec.rb | 125 +++++++++++++++++++++ spec/helpers/roles_helper_spec.rb | 15 +++ spec/models/assignment_spec.rb | 5 + spec/models/role_spec.rb | 5 + spec/requests/roles_spec.rb | 9 ++ spec/routing/roles_routing_spec.rb | 35 ++++++ spec/views/roles/edit.html.erb_spec.rb | 18 +++ spec/views/roles/index.html.erb_spec.rb | 19 ++++ spec/views/roles/new.html.erb_spec.rb | 18 +++ spec/views/roles/show.html.erb_spec.rb | 14 +++ 32 files changed, 540 insertions(+), 36 deletions(-) create mode 100644 app/controllers/roles_controller.rb create mode 100644 app/helpers/roles_helper.rb create mode 100644 app/models/assignment.rb create mode 100644 app/views/roles/_form.html.erb create mode 100644 app/views/roles/edit.html.erb create mode 100644 app/views/roles/index.html.erb create mode 100644 app/views/roles/new.html.erb create mode 100644 app/views/roles/show.html.erb delete mode 100644 db/migrate/20100901125550_users_have_and_belong_to_many_roles.rb rename db/migrate/{20100901125355_create_cancan_role_migration.rb => 20100902151516_create_roles.rb} (71%) create mode 100644 db/migrate/20100902151904_create_assignments.rb create mode 100644 db/migrate/20100902153434_generate_initial_roles.rb create mode 100644 features/manage_roles.feature create mode 100644 features/step_definitions/role_steps.rb create mode 100644 spec/controllers/roles_controller_spec.rb create mode 100644 spec/helpers/roles_helper_spec.rb create mode 100644 spec/models/assignment_spec.rb create mode 100644 spec/models/role_spec.rb create mode 100644 spec/requests/roles_spec.rb create mode 100644 spec/routing/roles_routing_spec.rb create mode 100644 spec/views/roles/edit.html.erb_spec.rb create mode 100644 spec/views/roles/index.html.erb_spec.rb create mode 100644 spec/views/roles/new.html.erb_spec.rb create mode 100644 spec/views/roles/show.html.erb_spec.rb diff --git a/Gemfile b/Gemfile index 2bb87dc..c836661 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,8 @@ gem 'mysql2' gem "devise", "~> 1.1.2" gem "devise_invitable", :git => "git://github.com/rymai/devise_invitable.git" gem 'capistrano' -gem 'formtastic', :git => "http://github.com/justinfrench/formtastic.git", :branch => "rails3" +gem 'formtastic', :git => "git://github.com/justinfrench/formtastic.git", :branch => "rails3" +gem 'declarative_authorization', :git => "git://github.com/stffn/declarative_authorization.git" # Use unicorn as the web server # gem 'unicorn' diff --git a/Gemfile.lock b/Gemfile.lock index bac2a65..47504f3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,4 +1,14 @@ GIT + remote: git://github.com/justinfrench/formtastic.git + revision: e42d256ebe7fdbd3881665d94ce54cf061a9186f + branch: rails3 + specs: + formtastic (1.1.0.beta) + actionpack (>= 2.3.0) + activesupport (>= 2.3.0) + i18n (>= 0.4.0) + +GIT remote: git://github.com/rspec/rspec-core.git revision: 001e6004bcaf94674184dc0d87869f060b6990a3 specs: @@ -42,14 +52,11 @@ GIT rails (~> 3.0.0) GIT - remote: http://github.com/justinfrench/formtastic.git - revision: eeba8d402721a3b3ae3c6e0d8f1b123fcae96b65 - branch: rails3 + remote: git://github.com/stffn/declarative_authorization.git + revision: 444439953f31b92e07c9fe7b7cef93fa2fe404ce specs: - formtastic (1.1.0.beta) - actionpack (>= 2.3.0) - activesupport (>= 2.3.0) - i18n (>= 0.4.0) + declarative_authorization (0.5) + rails (>= 2.1.0) GEM remote: http://rubygems.org/ @@ -184,6 +191,7 @@ DEPENDENCIES cucumber cucumber-rails database_cleaner + declarative_authorization! devise (~> 1.1.2) devise_invitable! formtastic! diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9de0f0e..2df2df8 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,9 +2,4 @@ class ApplicationController < ActionController::Base protect_from_forgery include SslRequirement - rescue_from CanCan::AccessDenied do |exception| - flash[:error] = exception.message - redirect_to root_url - end - end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb new file mode 100644 index 0000000..e064557 --- /dev/null +++ b/app/controllers/roles_controller.rb @@ -0,0 +1,83 @@ +class RolesController < ApplicationController + # GET /roles + # GET /roles.xml + def index + @roles = Role.all + + respond_to do |format| + format.html # index.html.erb + format.xml { render :xml => @roles } + end + end + + # GET /roles/1 + # GET /roles/1.xml + def show + @role = Role.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.xml { render :xml => @role } + end + end + + # GET /roles/new + # GET /roles/new.xml + def new + @role = Role.new + + respond_to do |format| + format.html # new.html.erb + format.xml { render :xml => @role } + end + end + + # GET /roles/1/edit + def edit + @role = Role.find(params[:id]) + end + + # POST /roles + # POST /roles.xml + def create + @role = Role.new(params[:role]) + + respond_to do |format| + if @role.save + format.html { redirect_to(@role, :notice => 'Role was successfully created.') } + format.xml { render :xml => @role, :status => :created, :location => @role } + else + format.html { render :action => "new" } + format.xml { render :xml => @role.errors, :status => :unprocessable_entity } + end + end + end + + # PUT /roles/1 + # PUT /roles/1.xml + def update + @role = Role.find(params[:id]) + + respond_to do |format| + if @role.update_attributes(params[:role]) + format.html { redirect_to(@role, :notice => 'Role was successfully updated.') } + format.xml { head :ok } + else + format.html { render :action => "edit" } + format.xml { render :xml => @role.errors, :status => :unprocessable_entity } + end + end + end + + # DELETE /roles/1 + # DELETE /roles/1.xml + def destroy + @role = Role.find(params[:id]) + @role.destroy + + respond_to do |format| + format.html { redirect_to(roles_url) } + format.xml { head :ok } + end + end +end diff --git a/app/helpers/roles_helper.rb b/app/helpers/roles_helper.rb new file mode 100644 index 0000000..6b6b6cc --- /dev/null +++ b/app/helpers/roles_helper.rb @@ -0,0 +1,2 @@ +module RolesHelper +end diff --git a/app/models/assignment.rb b/app/models/assignment.rb new file mode 100644 index 0000000..3878731 --- /dev/null +++ b/app/models/assignment.rb @@ -0,0 +1,4 @@ +class Assignment < ActiveRecord::Base + belongs_to :user + belongs_to :role +end diff --git a/app/models/role.rb b/app/models/role.rb index 0ade3d4..7edde25 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -1,4 +1,4 @@ class Role < ActiveRecord::Base - has_and_belongs_to_many :users + has_many :assignments + has_many :users, :through => :assignments end - diff --git a/app/models/user.rb b/app/models/user.rb index 0751749..18d9502 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -8,9 +8,12 @@ class User < ActiveRecord::Base # Setup accessible (or protected) attributes for your model attr_accessible :email, :password, :password_confirmation, :remember_me - has_and_belongs_to_many :roles + has_many :assignments + has_many :roles, :through => :assignments - def role?(role) - return !!self.roles.find_by_name(role.to_s.camelize) + def role_symbols + roles.map do |role| + role.name.underscore.to_sym + end end end diff --git a/app/views/roles/_form.html.erb b/app/views/roles/_form.html.erb new file mode 100644 index 0000000..645391a --- /dev/null +++ b/app/views/roles/_form.html.erb @@ -0,0 +1,21 @@ +<%= form_for(@role) do |f| %> + <% if @role.errors.any? %> +
+

<%= pluralize(@role.errors.count, "error") %> prohibited this role from being saved:

+ + +
+ <% end %> + +
+ <%= f.label :name %>
+ <%= f.text_field :name %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/roles/edit.html.erb b/app/views/roles/edit.html.erb new file mode 100644 index 0000000..cbe6f15 --- /dev/null +++ b/app/views/roles/edit.html.erb @@ -0,0 +1,6 @@ +

Editing role

+ +<%= render 'form' %> + +<%= link_to 'Show', @role %> | +<%= link_to 'Back', roles_path %> diff --git a/app/views/roles/index.html.erb b/app/views/roles/index.html.erb new file mode 100644 index 0000000..1f91b16 --- /dev/null +++ b/app/views/roles/index.html.erb @@ -0,0 +1,23 @@ +

Listing roles

+ + + + + + + + + +<% @roles.each do |role| %> + + + + + + +<% end %> +
Name
<%= role.name %><%= link_to 'Show', role %><%= link_to 'Edit', edit_role_path(role) %><%= link_to 'Destroy', role, :confirm => 'Are you sure?', :method => :delete %>
+ +
+ +<%= link_to 'New Role', new_role_path %> diff --git a/app/views/roles/new.html.erb b/app/views/roles/new.html.erb new file mode 100644 index 0000000..0900910 --- /dev/null +++ b/app/views/roles/new.html.erb @@ -0,0 +1,5 @@ +

New role

+ +<%= render 'form' %> + +<%= link_to 'Back', roles_path %> diff --git a/app/views/roles/show.html.erb b/app/views/roles/show.html.erb new file mode 100644 index 0000000..60c4c96 --- /dev/null +++ b/app/views/roles/show.html.erb @@ -0,0 +1,10 @@ +

<%= notice %>

+ +

+ Name: + <%= @role.name %> +

+ + +<%= link_to 'Edit', edit_role_path(@role) %> | +<%= link_to 'Back', roles_path %> diff --git a/config/routes.rb b/config/routes.rb index ef44241..e3ed262 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,6 @@ UKPortal::Application.routes.draw do + resources :roles + devise_for :users # The priority is based upon order of creation: diff --git a/db/migrate/20100901125550_users_have_and_belong_to_many_roles.rb b/db/migrate/20100901125550_users_have_and_belong_to_many_roles.rb deleted file mode 100644 index fbc6c5f..0000000 --- a/db/migrate/20100901125550_users_have_and_belong_to_many_roles.rb +++ /dev/null @@ -1,11 +0,0 @@ -class UsersHaveAndBelongToManyRoles < ActiveRecord::Migration - def self.up - create_table :roles_users, :id => false do |t| - t.references :role, :user - end - end - - def self.down - drop_table :roles_users - end -end diff --git a/db/migrate/20100901125355_create_cancan_role_migration.rb b/db/migrate/20100902151516_create_roles.rb similarity index 71% rename from db/migrate/20100901125355_create_cancan_role_migration.rb rename to db/migrate/20100902151516_create_roles.rb index 9e0914e..e0d1847 100644 --- a/db/migrate/20100901125355_create_cancan_role_migration.rb +++ b/db/migrate/20100902151516_create_roles.rb @@ -1,7 +1,8 @@ -class CreateCancanRoleMigration < ActiveRecord::Migration +class CreateRoles < ActiveRecord::Migration def self.up create_table :roles do |t| t.string :name + t.timestamps end end diff --git a/db/migrate/20100902151904_create_assignments.rb b/db/migrate/20100902151904_create_assignments.rb new file mode 100644 index 0000000..67a1020 --- /dev/null +++ b/db/migrate/20100902151904_create_assignments.rb @@ -0,0 +1,14 @@ +class CreateAssignments < ActiveRecord::Migration + def self.up + create_table :assignments do |t| + t.integer :user_id + t.integer :role_id + + t.timestamps + end + end + + def self.down + drop_table :assignments + end +end diff --git a/db/migrate/20100902153434_generate_initial_roles.rb b/db/migrate/20100902153434_generate_initial_roles.rb new file mode 100644 index 0000000..96e026f --- /dev/null +++ b/db/migrate/20100902153434_generate_initial_roles.rb @@ -0,0 +1,8 @@ +class GenerateInitialRoles < ActiveRecord::Migration + def self.up + Role.create(:name => 'admin') + end + + def self.down + end +end diff --git a/db/schema.rb b/db/schema.rb index a5eff84..9718590 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,17 +10,19 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20100901130613) do +ActiveRecord::Schema.define(:version => 20100902153434) do - create_table "roles", :force => true do |t| - t.string "name" + create_table "assignments", :force => true do |t| + t.integer "user_id" + t.integer "role_id" t.datetime "created_at" t.datetime "updated_at" end - create_table "roles_users", :id => false, :force => true do |t| - t.integer "role_id" - t.integer "user_id" + create_table "roles", :force => true do |t| + t.string "name" + t.datetime "created_at" + t.datetime "updated_at" end create_table "users", :force => true do |t| diff --git a/features/manage_roles.feature b/features/manage_roles.feature new file mode 100644 index 0000000..55c395c --- /dev/null +++ b/features/manage_roles.feature @@ -0,0 +1,47 @@ +Feature: Manage roles + In order to [goal] + [stakeholder] + wants [behaviour] + + Scenario: Register new role + Given I am on the new role page + When I fill in "Name" with "name 1" + And I press "Create" + Then I should see "name 1" + + # Rails generates Delete links that use Javascript to pop up a confirmation + # dialog and then do a HTTP POST request (emulated DELETE request). + # + # Capybara must use Culerity/Celerity or Selenium2 (webdriver) when pages rely + # on Javascript events. Only Culerity/Celerity supports clicking on confirmation + # dialogs. + # + # Since Culerity/Celerity and Selenium2 has some overhead, Cucumber-Rails will + # detect the presence of Javascript behind Delete links and issue a DELETE request + # instead of a GET request. + # + # You can turn this emulation off by tagging your scenario with @no-js-emulation. + # Turning on browser testing with @selenium, @culerity, @celerity or @javascript + # will also turn off the emulation. (See the Capybara documentation for + # details about those tags). If any of the browser tags are present, Cucumber-Rails + # will also turn off transactions and clean the database with DatabaseCleaner + # after the scenario has finished. This is to prevent data from leaking into + # the next scenario. + # + # Another way to avoid Cucumber-Rails' javascript emulation without using any + # of the tags above is to modify your views to use