dynamican 0.1.7 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6dd7da02224c7b3e20e8b582f5929657255d33d4ddf81037a09e2c303df7182
4
- data.tar.gz: 1c7f34c8b6335a89c21087243bdcaec746966ff76c7bc076204aefa736fce121
3
+ metadata.gz: ee2ebd9f3470a7ad1002ee3344a357fc1549e8065dffc09986f9c466577de8a9
4
+ data.tar.gz: e1cac4d8aa2b6f209dc6885cebe31d9ec5548af8578514aa9bf44fe1836fb697
5
5
  SHA512:
6
- metadata.gz: ea646968f0358bada82722bda78c2895bd6763428823f02ab51866caedbd45e7af0f411b5e77850e2bb71f83751503922aed96cb39b906fd344ebcca453154d9
7
- data.tar.gz: 3c29cc459e4aff80101d2ec436deba04c3600410e030cc4e3cf09ad575df8b3cd1f93602a8639937930733c82513a6ea8293eeddbb309cd9cb5afe7159bfd329
6
+ metadata.gz: 63e6761a9fed8385830c6f10697a0448ec08a8e2a781612ac54544ed810635bbfec6006c26e5054b653131a495815c6da5ed1842e11262736f9b1a274c9b0882
7
+ data.tar.gz: be88310e037fb8cb2e71af8f8616f1441a2963b4b65a6599762e92b6800e30cec6ede2216c5558d2ff8c8ffc7407c94e866c5894a3f8e15c31517dcb213ac5a6
data/README.md CHANGED
@@ -1,30 +1,26 @@
1
1
  # Dynamican
2
- Dynamican is a flexible gem to introduce permissions on rails applications. It is very customizable because it stores all the rules inside the database and can be added to multiple models: for example you can add permissions to your Role model or to users. With a couple of overrides you can also add permissions to both Role and User and use role permissions through user.
2
+ Dynamican is a flexible gem which introduces permissions on rails applications. It is very customizable because it stores all the rules inside the database and can be added to multiple models: for example you can add permissions to your Role and User models. With a couple of overrides you can also add permissions to both Role and User and allow user to use its roles permissions.
3
3
 
4
4
  ## Installation
5
5
  Inside your Gemfile put
6
6
 
7
7
  gem 'dynamican'
8
8
 
9
- then run `bundle install`
9
+ and run `bundle install`, then you can launch the following command.
10
10
 
11
- Once you have the gem, open the source code and look for migrations folder. You need to create in your project those migrations and run them. Obviously if you already have the gem installed and you are only updating, you only need to create the migrations for the later versions of the gem.
11
+ rails g dynamican_migration
12
12
 
13
- In each model you want to have the feature, just put
13
+ This command will generate a migration file in your project, which you can run with
14
14
 
15
- include Dynamican::Model
15
+ rails db:migrate
16
16
 
17
- Create `config/dynamican.yml` file and compile it as follows for each of the models you included the code above into (let's say for instance you included Dynamican::Model into User and Role models)
17
+ In each model you want to have the feature, just put the following.
18
18
 
19
- associations:
20
- role:
21
- class_name: 'Role'
22
- user:
23
- class_name: 'User'
19
+ include Dynamican::Model
24
20
 
25
- ### Using permissions on one model through another model
21
+ ### Using a model permissions on another model
26
22
 
27
- I wanted to have the possibility to assign permissions both directly to my User model and my Role model, so that if the User had one permission and one of its Role had another, the User could benefit from both. So i assigned the feature (as explained above) to both models and then decorated my User model like this
23
+ I wanted to have the possibility to assign permissions both directly to my User model and my Role model, so that if the User had one permission and one of its Roles had another, the User could benefit from both. So i included the feature into both models and then decorated my User model like following.
28
24
 
29
25
  module Decorators
30
26
  module Models
@@ -32,16 +28,11 @@ I wanted to have the possibility to assign permissions both directly to my User
32
28
  module DynamicanOverrides
33
29
  def self.prepended(base)
34
30
  base.class_eval do
35
- has_many :user_permission_connectors, class_name: 'Dynamican::PermissionConnector'
36
- has_many :user_permissions, class_name: 'Dynamican::Permission', through: :user_permission_connectors, source: :permission
31
+ has_many :user_permissions, class_name: 'Dynamican::Permission', as: :permittable, inverse_of: :permittable, foreign_key: :permittable_id
37
32
  has_many :role_permissions, through: :roles, class_name: 'Dynamican::Permission', source: :permissions
38
33
  end
39
34
  end
40
35
 
41
- def permission_connectors
42
- Dynamican::PermissionConnector.where(id: user_permission_connectors.ids + roles.map(&:permission_connectors).flatten.map(&:id))
43
- end
44
-
45
36
  def permissions
46
37
  Dynamican::Permission.where(id: user_permissions.ids + role_permissions.ids)
47
38
  end
@@ -52,67 +43,84 @@ I wanted to have the possibility to assign permissions both directly to my User
52
43
  end
53
44
  end
54
45
 
55
- I personally have put this in `app/decorators/models/user/dynamican_overrides.rb` (you need to load the folder if you don't already have it) but you can make it work as you please. I recommend to keep it separate from the original User model though.
46
+ I personally have put this in `app/decorators/models/user/dynamican_overrides.rb` (rails needs to load the folder of course); you can make it work as you please but i recommend to keep it separate from the original User model.
56
47
 
57
48
  ## Usage
58
49
 
59
50
  Now the hard part: the real configuration.
60
51
 
61
- Create one `Dynamican::Permission` for each pair of action-object you need. For example i created CRUD permissions for my models. Let's say, for instance, you have the Order model.
52
+ Create one `Dynamican::Action` for each action you need. For example i created CRUD permissions.
53
+
54
+ a1 = Dynamican::Action.create(name: 'create')
55
+ a2 = Dynamican::Action.create(name: 'read')
56
+ a3 = Dynamican::Action.create(name: 'update')
57
+ a4 = Dynamican::Action.create(name: 'delete')
62
58
 
63
- p1 = Dynamican::Permission.create(action: 'create', object_name: 'order')
64
- p2 = Dynamican::Permission.create(action: 'read', object_name: 'order')
65
- p3 = Dynamican::Permission.create(action: 'update', object_name: 'order')
66
- p4 = Dynamican::Permission.create(action: 'delete', object_name: 'order')
59
+ Then create one `Dynamican::Item` for each resource you want your permittables to have permissions to act on. This is not mandatory for every permission though: you can also set a permission to do a general action, like `login`. Right now i'm trying to setup permissions for my permittable (Role model) to act on Order model.
67
60
 
68
- To assign one of these permissions to your Role or User, you need to create a `Dynamican::PermissionConnector` like this
61
+ i1 = Dynamican::Item.create(name: 'Order')
69
62
 
70
- user.permission_connectors.create(permission: p1)
63
+ NOTE: conventionally, the name should be PascalCase, so there is a `before_validation` hook that classifies the name you are setting.
71
64
 
72
- Or simply
65
+ Create one `Dynamican::Permission` for each action you want your `role` instance to have permissions for.
73
66
 
74
- user.permissions << p1
67
+ p1 = Dynamican::Permission.create(action: a1, items: [i1], permittable: role)
68
+ p2 = Dynamican::Permission.create(action: a2, items: [i1], permittable: role)
69
+ p3 = Dynamican::Permission.create(action: a3, items: [i1], permittable: role)
70
+ p4 = Dynamican::Permission.create(action: a4, items: [i1], permittable: role)
75
71
 
76
- Now your user is considered able to create orders and you can check the permissions:
72
+ Now your Role is considered able to create, read, update and destroy orders; you can evaluate permissions with `can?` method.
77
73
 
78
- user.can? :create, :order
79
- # Returns true
74
+ role.can? :create, :order
80
75
 
81
- user.can? :read, :order
82
- # Returns false
76
+ # true
83
77
 
84
- You can pass as second argument (the object) a symbol, a string, the class itself and also the instance (instances are used for condition evaluations).
85
- You can also pass an array of these elements and permissions for all elements will be evaluated. The `can?` method will return true only if all permissions are evaluated positively.
86
- You can also create custom permissions which don't need an object, simply leaving the `object_name` empty. Let's say you want to give permission to a certain user to dance
78
+ role.can? :else, :order
87
79
 
88
- p5 = Dynamican::Permission.create(action: 'dance')
80
+ # false
89
81
 
90
- user.permissions << p5
82
+ You can pass as second argument (the item) a symbol, a string, the class itself and also the instance (instances are required for condition evaluations).
83
+ If you pass an array of these elements, permissions for all single element will be evaluated. The `can?` method will return true only if permissions to all items are evaluated positively.
84
+ You can also create custom permissions which don't need an item, (item is not required for permission creation). Let's say you want to give permission to a certain `user` to dance.
85
+
86
+ action_dance = Dynamican::Action.create(name: 'dance')
87
+ p5 = Dynamican::Permission.create(action: action_dance, permittable: user)
91
88
 
92
89
  Call the `can?` method without any second argument
93
90
 
94
91
  user.can? :dance
95
92
 
96
- # Returns true
93
+ # true
97
94
 
98
95
 
99
- ## Conditions
96
+ ### Conditions
100
97
 
101
- You can link a `Dynamican::PermissionConnector` to as many conditions as you want.
98
+ You can link a `Dynamican::Permission` to as many conditions as you want. A permission having at least one condition linked to is considered conditional (Permission class have `conditional` and `unconditional` scopes)
102
99
 
103
- Conditions are created like this
100
+ Conditions are created like this.
104
101
 
105
- permission_connector.conditions.create(statement: '@user.orders.count < 5')
106
- permission_connector.conditions.create(statement: '@object.field.present?')
102
+ permission.conditions.create(statement: '@user.orders.count < 5')
103
+ permission.conditions.create(statement: '@item.field.present?')
107
104
 
108
- You can store in conditions statements whatever conditions you like in plain ruby and the string will be evaulated. Inside the statements, object have to be called as instance variables. These instance variables need to be present and can be declared as follows:
105
+ You can store in conditions statements whatever conditions you like in plain ruby and the string will be evaulated. Inside the statements, object have to be called as instance variables. These instance variables indeed need to be present and can be declared in a few ways.
109
106
 
110
- 1. The model name of the instance you called `can?` from, like the user, will be defined automatically based on model name so if you call `user.can?` you will have `@user` variable defined.
111
- 2. The object you pass as second argument (which should match the `object_name` of your permission) will be defined as `@object`, so if you call `user.can? :read, @order` you will have `@object` variable defined containing your `@order`.
107
+ 1. The model name of the instance you called `can?` from, like the user, will be defined automatically based both on a fixed name and on model name, so if you call `user.can?` you will have `@subject` variable (this is fixed) and `@user` variable defined because user is of class `User` (namespaces get cut out, so `Something::User` still turne into `@user`).
108
+ 2. The same thing happens with the item: it will be defined both as `@item` and as the name of its class, so if you call `user.can? :read, @order` you will have `@item` and `@order` variable defined containing your `@order` object.
112
109
  3. You can pass as third argument an hash of objects like this `user.can? :read, @order, time: Time.zone.now, whatever: @you_want` and you will have `@time` and `@whatever` variables defined.
113
110
 
114
- WARNING: since the condition statement gets evaluated, i recommend not to allow anyone except project developers to create conditions to prevent malicious code from being executed.
111
+ WARNING: since the condition statement gets evaluated, i recommend not to allow anyone except project developers to create conditions, in order to prevent malicious code from being executed.
115
112
 
116
- If one `Dynamican::PermissionConnector` is linked to many conditions, the model will be allowed to make that action only if all conditions are true. If you want to set alternative conditions, you should store the or conditions inside the same statement, like this:
113
+ If one `Dynamican::Permission` is linked to many conditions, the model will be allowed to make that action only if all conditions are true. If you want to set alternative conditions, you should store the `or` conditions inside the same condition statement, like this:
117
114
 
118
115
  condition.statement = '@user.nice? || @user.polite?'
116
+
117
+ ### Permission scopes
118
+
119
+ You can apply the scope `for_action(action_name)` to Permission to find permissions bound to a specific action.
120
+ There is a `for_item(item_name)` scope, which turns to string and then classifies automatically the argument to match it with the classified item name. The scope filters all Permission records that have an item with the specified name in its items list.
121
+ There is also a `without_item` scope to filter records that are not linked to any item.
122
+ As mentioned before, you can also use `conditional` and `unconditional` scopes to find objects with or without any condition attached.
123
+
124
+ ### Controller usage
125
+
126
+ Your controllers now all have the `authorize!` method, which accepts one or two arguments: the first is the action, and the second (optional) is the item (or list of items) you want to check permissions for. As you can see, the usage is similar to the `can?` method. The reason is that is actually calls that method on the instance of `@current_user` and, whether permissions are evaluated as false, it raises an exception which is rescued by an `unauthorized` response rendered.
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'dynamican'
3
- s.version = '0.1.7'
4
- s.date = '2020-04-12'
3
+ s.version = '1.0.1'
4
+ s.date = '2020-09-10'
5
5
  s.summary = "Dynamic permissions"
6
6
  s.description = "Dynamic and flexible database configurable permissions for your application"
7
7
  s.authors = ["Valerio Bellaveglia"]
@@ -1,6 +1,8 @@
1
- require 'dynamican/configuration'
1
+ require 'dynamican/authorization'
2
2
  require 'dynamican/evaluator'
3
3
  require 'dynamican/model'
4
- require 'models/dynamican/condition'
5
- require 'models/dynamican/permission_connector'
6
4
  require 'models/dynamican/permission'
5
+ require 'models/dynamican/action'
6
+ require 'models/dynamican/item'
7
+ require 'models/dynamican/condition'
8
+ require 'generators/dynamican_migration_generator'
@@ -0,0 +1,25 @@
1
+ module Dynamican
2
+ module Authorization
3
+ extend ActiveSupport::Concern
4
+
5
+ class UnauthorizedResource < StandardError; end
6
+
7
+ included do
8
+ rescue_from UnauthorizedResource, with: :unauthorized
9
+ end
10
+
11
+ def authorize!(action, item = nil)
12
+ raise UnauthorizedResource unless @current_user.can? action, item
13
+ end
14
+
15
+ def unauthorized
16
+ render status: :unauthorized
17
+ end
18
+ end
19
+ end
20
+
21
+ if defined? ActiveSupport
22
+ ActiveSupport.on_load(:action_controller) do
23
+ include Dynamican::Authorization
24
+ end
25
+ end
@@ -1,42 +1,41 @@
1
1
  module Dynamican
2
2
  class Evaluator
3
- attr_reader :subject, :action, :object, :object_name, :conditions_instances
3
+ attr_reader :subject, :action, :item, :item_name, :conditions_instances
4
4
 
5
- def initialize(subject, action, object, conditions_instances = {})
5
+ def initialize(subject, action, item, conditions_instances = {})
6
6
  @subject = subject
7
7
  @action = action
8
- @object = object
9
- @object_name = calculate_object_name
8
+ @item = item
9
+ @item_name = calculate_item_name
10
10
  @conditions_instances = conditions_instances
11
11
  end
12
12
 
13
13
  def evaluate
14
14
  set_instance_variables
15
15
 
16
- matching_connectors = subject.permission_connectors.for_action(action).for_object(object_name)
17
- matching_conditions_statements = matching_connectors.conditional.map(&:conditions).flatten.map(&:statement)
16
+ matching_permissions = item.present? ? subject.permissions.for_action(action).for_item(item_name) : subject.permissions.for_action(action).without_item
17
+ matching_permissions_statements = matching_permissions.conditional.map(&:conditions).flatten.map(&:statement)
18
18
 
19
- matching_connectors.unconditional.any? ||
20
- matching_conditions_statements.any? && matching_conditions_statements.map { |statement| eval statement }.all?
19
+ matching_permissions.unconditional.any? ||
20
+ matching_permissions_statements.any? && matching_permissions_statements.map { |statement| eval statement }.all?
21
21
  end
22
22
 
23
23
  private
24
24
 
25
25
  def set_instance_variables
26
- instance_variable_set("@#{subject.model_name.element}", subject)
26
+ instance_variable_set("@#{subject.class.name.demodulize.underscore}", subject)
27
+ instance_variable_set("@#{item.class.name.demodulize.underscore}", item)
27
28
 
28
- conditions_instances.each do |instance_name, instance_object|
29
- instance_variable_set("@#{instance_name}", instance_object)
29
+ conditions_instances.each do |instance_name, instance_item|
30
+ instance_variable_set("@#{instance_name}", instance_item)
30
31
  end
31
32
  end
32
33
 
33
- def calculate_object_name
34
- if object.class.in? [Symbol, String, Class]
35
- object.to_s.downcase
36
- elsif object.is_a?(NilClass)
37
- nil
34
+ def calculate_item_name
35
+ if item.class.in? [Symbol, String, Class]
36
+ item.to_s.classify
38
37
  else
39
- object.class.to_s.downcase
38
+ item.class.name.demodulize
40
39
  end
41
40
  end
42
41
  end
@@ -3,15 +3,14 @@ module Dynamican
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- has_many :permission_connectors, class_name: 'Dynamican::PermissionConnector'
7
- has_many :permissions, class_name: 'Dynamican::Permission', through: :permission_connectors, source: :permission
6
+ has_many :permissions, class_name: 'Dynamican::Permission', as: :permittable, dependent: :destroy
8
7
  end
9
8
 
10
- def can?(action, object = nil, conditions_instances = {})
11
- if object.respond_to? :each
12
- object.all? { |single_object| can? action, single_object }
9
+ def can?(action, item = nil, conditions_instances = {})
10
+ if item.respond_to? :each
11
+ item.all? { |single_item| can? action, single_item }
13
12
  else
14
- Dynamican::Evaluator.new(self, action, object, conditions_instances).evaluate
13
+ Dynamican::Evaluator.new(self, action, item, conditions_instances).evaluate
15
14
  end
16
15
  end
17
16
  end
@@ -0,0 +1,53 @@
1
+ require 'rails/generators'
2
+
3
+ class DynamicanMigrationGenerator < Rails::Generators::Base
4
+
5
+ def create_migration_file
6
+ create_file "db/migrate/#{Time.zone.now.strftime("%Y%m%d%H%M%S")}_dynamican_migration.rb", migration_data
7
+ end
8
+
9
+ private
10
+
11
+ def migration_data
12
+ <<MIGRATION
13
+ class DynamicanMigration < ActiveRecord::Migration[5.2]
14
+ def change
15
+ unless table_exists? :permissions
16
+ create_table :permissions do |t|
17
+ t.bigint :permittable_id
18
+ t.string :permittable_type
19
+ t.bigint :action_id
20
+
21
+ t.timestamps
22
+ end
23
+
24
+ create_table :actions do |t|
25
+ t.string :name
26
+
27
+ t.timestamps
28
+ end
29
+
30
+ create_table :items do |t|
31
+ t.string :name
32
+
33
+ t.timestamps
34
+ end
35
+
36
+ create_table :conditions do |t|
37
+ t.bigint :permission_id
38
+ t.string :statement
39
+ t.string :description
40
+
41
+ t.timestamps
42
+ end
43
+
44
+ create_table :items_permissions do |t|
45
+ t.bigint :item_id
46
+ t.bigint :permission_id
47
+ end
48
+ end
49
+ end
50
+ end
51
+ MIGRATION
52
+ end
53
+ end
@@ -0,0 +1,9 @@
1
+ module Dynamican
2
+ class Action < ActiveRecord::Base
3
+ has_many :permissions, class_name: 'Dynamican::Permission', inverse_of: :action, foreign_key: :action_id, dependent: :destroy
4
+
5
+ validates :name, presence: true, uniqueness: true
6
+
7
+ attr_readonly :name
8
+ end
9
+ end
@@ -1,5 +1,7 @@
1
1
  module Dynamican
2
2
  class Condition < ActiveRecord::Base
3
- has_and_belongs_to_many :permission_connectors, class_name: 'Dynamican::PermissionConnector', foreign_key: :condition_id
3
+ belongs_to :permission, class_name: 'Dynamican::Permission', inverse_of: :conditions, foreign_key: :permission_id
4
+
5
+ validates_presence_of :statement
4
6
  end
5
7
  end
@@ -0,0 +1,15 @@
1
+ module Dynamican
2
+ class Item < ActiveRecord::Base
3
+ has_and_belongs_to_many :permissions, class_name: 'Dynamican::Permission', inverse_of: :items, foreign_key: :item_id, dependent: :destroy
4
+
5
+ validates :name, presence: true, uniqueness: true
6
+
7
+ attr_readonly :name
8
+
9
+ before_validation :classify_name
10
+
11
+ def classify_name
12
+ self.name = self.name.classify
13
+ end
14
+ end
15
+ end
@@ -1,10 +1,14 @@
1
1
  module Dynamican
2
2
  class Permission < ActiveRecord::Base
3
- has_many :permission_connectors, class_name: 'Dynamican::PermissionConnector', inverse_of: :permission, foreign_key: :permission_id
3
+ belongs_to :permittable, polymorphic: true
4
+ belongs_to :action, class_name: 'Dynamican::Action', inverse_of: :permissions, foreign_key: :action_id
5
+ has_and_belongs_to_many :items, class_name: 'Dynamican::Item', inverse_of: :permissions, foreign_key: :permission_id
6
+ has_many :conditions, class_name: 'Dynamican::Condition', inverse_of: :permission, foreign_key: :permission_id
4
7
 
5
- validates_presence_of :action
6
-
7
- scope :for_action, -> (actions) { where(action: actions) }
8
- scope :for_object, -> (object_names) { where(object_name: object_names) }
8
+ scope :for_action, -> (action_name) { joins(:action).where(actions: { name: action_name }) }
9
+ scope :for_item, -> (item_name) { joins(:items).where(items: { name: item_name.to_s.classify }) }
10
+ scope :without_item, -> { left_outer_joins(:items).where(items: { id: nil }) }
11
+ scope :conditional, -> { joins(:conditions) }
12
+ scope :unconditional, -> { left_outer_joins(:conditions).where(conditions: { id: nil }) }
9
13
  end
10
14
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamican
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Valerio Bellaveglia
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-12 00:00:00.000000000 Z
11
+ date: 2020-09-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Dynamic and flexible database configurable permissions for your application
14
- email:
14
+ email:
15
15
  executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
@@ -20,18 +20,19 @@ files:
20
20
  - README.md
21
21
  - dynamican.gemspec
22
22
  - lib/dynamican.rb
23
- - lib/dynamican/configuration.rb
23
+ - lib/dynamican/authorization.rb
24
24
  - lib/dynamican/evaluator.rb
25
25
  - lib/dynamican/model.rb
26
+ - lib/generators/dynamican_migration_generator.rb
27
+ - lib/models/dynamican/action.rb
26
28
  - lib/models/dynamican/condition.rb
29
+ - lib/models/dynamican/item.rb
27
30
  - lib/models/dynamican/permission.rb
28
- - lib/models/dynamican/permission_connector.rb
29
- - migrations/0.1.2/dynamican_create_database_structure.rb
30
31
  homepage: https://github.com/ValerioBellaveglia/Dynamican
31
32
  licenses:
32
33
  - MIT
33
34
  metadata: {}
34
- post_install_message:
35
+ post_install_message:
35
36
  rdoc_options: []
36
37
  require_paths:
37
38
  - lib
@@ -46,8 +47,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
47
  - !ruby/object:Gem::Version
47
48
  version: '0'
48
49
  requirements: []
49
- rubygems_version: 3.0.2
50
- signing_key:
50
+ rubygems_version: 3.1.2
51
+ signing_key:
51
52
  specification_version: 4
52
53
  summary: Dynamic permissions
53
54
  test_files: []
@@ -1,17 +0,0 @@
1
- module Dynamican
2
- def self.configuration
3
- @configuration ||= Configuration.new(configuration_hash)
4
- end
5
-
6
- def self.configuration_hash
7
- @configuration_hash ||= HashWithIndifferentAccess.new(YAML.load_file('config/dynamican.yml'))
8
- end
9
-
10
- class Configuration
11
- attr_accessor :associations
12
-
13
- def initialize(configuration_hash)
14
- @associations = configuration_hash[:associations]
15
- end
16
- end
17
- end
@@ -1,14 +0,0 @@
1
- module Dynamican
2
- class PermissionConnector < ActiveRecord::Base
3
- Dynamican.configuration.associations.each do |association_name, association_options|
4
- belongs_to association_name.to_sym, class_name: association_options[:class_name], inverse_of: association_options[:inverse_of], foreign_key: "#{association_name}_id".to_sym, optional: true
5
- end
6
- has_and_belongs_to_many :conditions, class_name: 'Dynamican::Condition', inverse_of: :permission_connectors, foreign_key: :permission_connector_id
7
- belongs_to :permission, class_name: 'Dynamican::Permission', inverse_of: :permission_connectors, foreign_key: :permission_id
8
-
9
- scope :conditional, -> { where(conditional: true) }
10
- scope :unconditional, -> { where(conditional: false) }
11
- scope :for_action, -> (action) { joins(:permission).where(permissions: { action: action }) }
12
- scope :for_object, -> (object_name) { joins(:permission).where(permissions: { object_name: object_name }) }
13
- end
14
- end
@@ -1,31 +0,0 @@
1
- class DynamicanCreateDatabaseStructure < ActiveRecord::Migration[5.2]
2
- def change
3
- create_table :conditions do |t|
4
- t.string :description
5
- t.string :statement
6
-
7
- t.timestamps
8
- end
9
-
10
- create_table :permissions do |t|
11
- t.string :action
12
- t.string :object_name
13
-
14
- t.timestamps
15
- end
16
-
17
- create_table :permission_connectors do |t|
18
- t.references :user
19
- t.references :role
20
- t.references :permission
21
- t.boolean :conditional, default: false
22
-
23
- t.timestamps
24
- end
25
-
26
- create_table :conditions_permission_connectors do |t|
27
- t.bigint :condition_id
28
- t.bigint :permission_connector_id
29
- end
30
- end
31
- end