From c0ad4a9572e249d820a0a752403a64c472c5d4e9 Mon Sep 17 00:00:00 2001 From: Jeremy Zheng Date: Mon, 3 Jul 2017 14:30:10 -0700 Subject: [PATCH] rolify --- Gemfile | 2 ++ Gemfile.lock | 4 +++ app/models/ability.rb | 35 +++++++++++++++++++ app/models/role.rb | 13 +++++++ app/models/user.rb | 2 ++ config/initializers/rolify.rb | 7 ++++ .../20170703212023_rolify_create_roles.rb | 19 ++++++++++ db/schema.rb | 21 ++++++++++- db/seeds.rb | 4 ++- test/fixtures/roles.yml | 11 ++++++ test/models/role_test.rb | 7 ++++ 11 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 app/models/ability.rb create mode 100644 app/models/role.rb create mode 100644 config/initializers/rolify.rb create mode 100644 db/migrate/20170703212023_rolify_create_roles.rb create mode 100644 test/fixtures/roles.yml create mode 100644 test/models/role_test.rb diff --git a/Gemfile b/Gemfile index 35e9ac6..9d8212e 100644 --- a/Gemfile +++ b/Gemfile @@ -67,3 +67,5 @@ gem 'country_select' gem 'devise' gem 'devise-i18n' gem 'omniauth-facebook' +gem 'cancancan' +gem 'rolify' diff --git a/Gemfile.lock b/Gemfile.lock index 96710b0..dc4b4be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -65,6 +65,7 @@ GEM bindex (0.5.0) builder (3.2.3) byebug (9.0.6) + cancancan (2.0.0) capybara (2.14.4) addressable mime-types (>= 1.16) @@ -191,6 +192,7 @@ GEM responders (2.4.0) actionpack (>= 4.2.0, < 5.3) railties (>= 4.2.0, < 5.3) + rolify (5.1.0) ruby_dep (1.5.0) rubyzip (1.2.1) sass (3.4.24) @@ -251,6 +253,7 @@ PLATFORMS DEPENDENCIES bootstrap! byebug + cancancan capybara (~> 2.13) coffee-rails (~> 4.2) country_select @@ -265,6 +268,7 @@ DEPENDENCIES puma (~> 3.7) rails (~> 5.1.2) rails-i18n! + rolify sass-rails (~> 5.0) selenium-webdriver simple_form diff --git a/app/models/ability.rb b/app/models/ability.rb new file mode 100644 index 0000000..41ed6d9 --- /dev/null +++ b/app/models/ability.rb @@ -0,0 +1,35 @@ +class Ability + include CanCan::Ability + + def initialize(user) + # Define abilities for the passed in user here. For example: + # + user ||= User.new # guest user (not logged in) + if user.is_admin? + can :manage, :all + else + can :read, :all + # can :read, Forum + # can :write, Forum if user.has_role?(:moderator, Forum) + # can :write, Forum, :id => Forum.with_role(:moderator, user).pluck(:id) + end + # + # The first argument to `can` is the action you are giving the user + # permission to do. + # If you pass :manage it will apply to every action. Other common actions + # here are :read, :create, :update and :destroy. + # + # The second argument is the resource the user can perform the action on. + # If you pass :all it will apply to every resource. Otherwise pass a Ruby + # class of the resource. + # + # The third argument is an optional hash of conditions to further filter the + # objects. + # For example, here the user can only update published articles. + # + # can :update, Article, :published => true + # + # See the wiki for details: + # https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities + end +end diff --git a/app/models/role.rb b/app/models/role.rb new file mode 100644 index 0000000..bacd2b7 --- /dev/null +++ b/app/models/role.rb @@ -0,0 +1,13 @@ +class Role < ApplicationRecord + has_and_belongs_to_many :users, :join_table => :users_roles + + belongs_to :resource, + :polymorphic => true, + :optional => true + + validates :resource_type, + :inclusion => { :in => Rolify.resource_types }, + :allow_nil => true + + scopify +end diff --git a/app/models/user.rb b/app/models/user.rb index 359b384..ae7a205 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,4 +1,6 @@ class User < ApplicationRecord + rolify + # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, diff --git a/config/initializers/rolify.rb b/config/initializers/rolify.rb new file mode 100644 index 0000000..a117243 --- /dev/null +++ b/config/initializers/rolify.rb @@ -0,0 +1,7 @@ +Rolify.configure do |config| + # By default ORM adapter is ActiveRecord. uncomment to use mongoid + # config.use_mongoid + + # Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false + config.use_dynamic_shortcuts +end \ No newline at end of file diff --git a/db/migrate/20170703212023_rolify_create_roles.rb b/db/migrate/20170703212023_rolify_create_roles.rb new file mode 100644 index 0000000..666c1e2 --- /dev/null +++ b/db/migrate/20170703212023_rolify_create_roles.rb @@ -0,0 +1,19 @@ +class RolifyCreateRoles < ActiveRecord::Migration[5.1] + def change + create_table(:roles) do |t| + t.string :name + t.references :resource, :polymorphic => true + + t.timestamps + end + + create_table(:users_roles, :id => false) do |t| + t.references :user + t.references :role + end + + add_index(:roles, :name) + add_index(:roles, [ :name, :resource_type, :resource_id ]) + add_index(:users_roles, [ :user_id, :role_id ]) + end +end diff --git a/db/schema.rb b/db/schema.rb index 8b9d837..694ab3e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,11 +10,22 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170703204501) do +ActiveRecord::Schema.define(version: 20170703212023) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "roles", force: :cascade do |t| + t.string "name" + t.string "resource_type" + t.bigint "resource_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id" + t.index ["name"], name: "index_roles_on_name" + t.index ["resource_type", "resource_id"], name: "index_roles_on_resource_type_and_resource_id" + end + create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false @@ -43,4 +54,12 @@ t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true end + create_table "users_roles", id: false, force: :cascade do |t| + t.bigint "user_id" + t.bigint "role_id" + t.index ["role_id"], name: "index_users_roles_on_role_id" + t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id" + t.index ["user_id"], name: "index_users_roles_on_user_id" + end + end diff --git a/db/seeds.rb b/db/seeds.rb index 4d7c526..532c235 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -8,4 +8,6 @@ root = User.new email:ENV['MANAGER'], name: 'root', password: 'changeme' root.skip_confirmation! -root.save \ No newline at end of file +root.save + +%w(root admin).each {|n| root.add_role n} diff --git a/test/fixtures/roles.yml b/test/fixtures/roles.yml new file mode 100644 index 0000000..80aed36 --- /dev/null +++ b/test/fixtures/roles.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/models/role_test.rb b/test/models/role_test.rb new file mode 100644 index 0000000..11c53a8 --- /dev/null +++ b/test/models/role_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class RoleTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end