databound 2.0.1 → 3.0.0

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
  SHA1:
3
- metadata.gz: cba727e2ab9d8e8ae6f7493aad47e28cac352592
4
- data.tar.gz: d6791304413633e2abdaee1b737a77b1a9dfaea3
3
+ metadata.gz: c17ea9293869f528bb57b8f815ade20dfe629904
4
+ data.tar.gz: bff389e7ba5502edb650bede3fe7b78acda3a88e
5
5
  SHA512:
6
- metadata.gz: 63143f0d64ad79f6563425cd35b7a73a4e01d0c3b40b369476c34f77c52d54c64a2793f57b68f39970c8031f6706df4fdb038aacfd29ff3fbccc58cb6f0d008a
7
- data.tar.gz: b6cdeca9c47ab71d89368ed45f2c10ee2f3eb715f693b3255264083982d25d9415c9fe1ee3723ae4ef947a5fb1ca81ab0cc682314d7c0ad4d953deb8c15e60e0
6
+ metadata.gz: ac22d42e131278f67c5fa25dbcfeeb3f8e8300c1596d47ddf5493cb19daab2a9cc3cd05519ed5a8b780ba703db670bffaea15144ac66ab364d9807bf6553eeb4
7
+ data.tar.gz: 2c4d73542e0f1195e9e1ebc0aebeb6cd366c2f77b526e347d160225694b4c03b15b4882ef5cb21b4c799c70fed73122996217084725fe44bdce56eabfa26631a
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  ![Databound](https://cloud.githubusercontent.com/assets/1877286/4743542/df89dcec-5a28-11e4-9114-6f383fe269cb.png)
8
8
 
9
- Exposes Ruby on Rails database to the Javascript side.
9
+ Provides Javascript a simple CRUD API to the Ruby on Rails backend.
10
10
 
11
11
  This repo is for Ruby on Rails backend part of Databound.
12
12
 
@@ -24,11 +24,11 @@ This repo is for Ruby on Rails backend part of Databound.
24
24
  });
25
25
 
26
26
  User.find(15).then(function(user) {
27
- print('User no. 15: ' + user.name);
27
+ alert('User no. 15: ' + user.name);
28
28
  });
29
29
 
30
30
  User.create({ name: 'Peter' }).then(function(user) {
31
- print('I am ' + user.name + ' from database');
31
+ alert('I am ' + user.name + ' from database');
32
32
  });
33
33
  ```
34
34
 
data/databound.gemspec CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Databound::VERSION
9
9
  spec.authors = ['Domas Bitvinskas']
10
10
  spec.email = ['domas.bitvinskas@me.com']
11
- spec.summary = %q{Databound exposes Ruby on Rails database to the Javascript side}
12
- spec.description = %q{Works with ActiveRecord and Mongoid out of the box}
13
- spec.homepage = 'https://github.com/Nedomas/databound'
11
+ spec.summary = %q{Provides Javascript a simple API to the Ruby on Rails CRUD}
12
+ spec.description = %q{It lets you use methods like create, update, destroy in the front-end while handling all the setup and providing basic security out of the box.}
13
+ spec.homepage = 'http://databound.me'
14
14
  spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
data/lib/databound.rb CHANGED
@@ -2,13 +2,13 @@ require 'databound/extensions'
2
2
  require 'databound/version'
3
3
  require 'databound/data'
4
4
  require 'databound/manager'
5
- require 'databound/utils'
5
+ require 'databound/config'
6
+ require 'databound/controller'
6
7
  require 'databound/rails/routes'
7
8
 
8
9
  module Databound
9
10
  def self.included(base)
10
11
  base.send(:before_action, :init_crud, only: %i(where create update destroy))
11
- base.extend(ClassMethods)
12
12
  end
13
13
 
14
14
  def where
@@ -66,14 +66,6 @@ module Databound
66
66
  serializer.new(record).attributes[:id]
67
67
  end
68
68
 
69
- def model
70
- raise 'Override model method to specify a model to be used in CRUD'
71
- end
72
-
73
- def permitted_columns
74
- []
75
- end
76
-
77
69
  def init_crud
78
70
  @crud = Databound::Manager.new(self)
79
71
  end
@@ -81,23 +73,4 @@ module Databound
81
73
  def scoped_records
82
74
  @crud.find_scoped_records(only_extra_scopes: true)
83
75
  end
84
-
85
- module ClassMethods
86
- attr_reader :dsls
87
- attr_reader :stricts
88
- attr_reader :permit_update_destroy
89
-
90
- def dsl(name, value, strict: true, &block)
91
- @stricts ||= {}
92
- @stricts[name.to_s] = strict
93
-
94
- @dsls ||= {}
95
- @dsls[name.to_s] ||= {}
96
- @dsls[name.to_s][value.to_s] = block
97
- end
98
-
99
- def permit_update_destroy?(&block)
100
- @permit_update_destroy = block
101
- end
102
- end
103
76
  end
@@ -0,0 +1,38 @@
1
+ module Databound
2
+ class Config
3
+ def initialize(block, model)
4
+ @model = model
5
+ @permit = {}
6
+ instance_eval(&block)
7
+ end
8
+
9
+ def columns(*specified_columns)
10
+ @columns = specified_columns
11
+ end
12
+
13
+ def model(specified_model)
14
+ raise "Model '#{@model}' already specified" if @model
15
+
16
+ @model = specified_model
17
+ end
18
+
19
+ def permit(*methods, &block)
20
+ methods.each do |method|
21
+ @permit[method] = block
22
+ end
23
+ end
24
+
25
+ def dsl(name, value, strict: true, &block)
26
+ @stricts ||= {}
27
+ @stricts[name] = strict
28
+
29
+ @dsls ||= {}
30
+ @dsls[name] ||= {}
31
+ @dsls[name][value.to_s] = block
32
+ end
33
+
34
+ def read(name)
35
+ instance_variable_get("@#{name}")
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,63 @@
1
+ module Databound
2
+ class Controller
3
+ class << self
4
+ def add_application_controller_configs!
5
+ def ApplicationController.databound(model = nil, &block)
6
+ include Databound
7
+
8
+ send(:define_method, :databound_config) do
9
+ Databound::Config.new(block, model)
10
+ end
11
+ end
12
+ end
13
+
14
+ def find_or_create(name, resource, opts)
15
+ find(name) || create(name, resource, opts)
16
+ end
17
+
18
+ def create(name, resource, opts)
19
+ opts ||= {}
20
+ Object.const_set(as_constant_string(name), new(resource, opts))
21
+ end
22
+
23
+ def new(resource, opts)
24
+ model_name = opts.delete(:model) || fallback_model(resource)
25
+
26
+ result = Class.new(ApplicationController)
27
+ result.send(:databound) do
28
+ model model_name
29
+
30
+ opts.each do |key, value|
31
+ send(key, *value)
32
+ end
33
+ end
34
+
35
+ result
36
+ end
37
+
38
+ def fallback_model(resource)
39
+ resource.to_s.classify.underscore.to_sym
40
+ end
41
+
42
+ def exists?(path)
43
+ name_error = false
44
+
45
+ begin
46
+ as_constant_string(path).constantize
47
+ rescue NameError
48
+ name_error = true
49
+ end
50
+
51
+ !name_error
52
+ end
53
+
54
+ def find(path)
55
+ as_constant_string(path).constantize if exists?(path)
56
+ end
57
+
58
+ def as_constant_string(name)
59
+ "#{name.camelize}Controller"
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,16 +1,16 @@
1
1
  module Databound
2
2
  class Data
3
- def initialize(controller, json)
3
+ def initialize(controller, json, model)
4
4
  return unless json
5
5
 
6
6
  @controller = controller
7
- @params = JSON.parse(json) if json.is_a?(String)
8
- @params = json if json.is_a?(Hash)
7
+ @json = json
9
8
  @data = interpolated_params
9
+ @model = model
10
10
  end
11
11
 
12
- def records(model)
13
- model.where(@data)
12
+ def records
13
+ @model.where(@data)
14
14
  end
15
15
 
16
16
  def to_h
@@ -19,21 +19,27 @@ module Databound
19
19
 
20
20
  private
21
21
 
22
+ def params
23
+ @params ||= JSON.parse(@json) if @json.is_a?(String)
24
+ @params ||= @json if @json.is_a?(Hash)
25
+ OpenStruct.new(@params)
26
+ end
27
+
22
28
  def interpolated_params
23
- @params.each_with_object({}) do |(key, val), obj|
29
+ params.to_h.each_with_object({}) do |(key, val), obj|
24
30
  check_strict!(key, val)
25
31
 
26
32
  block = dsl_block(key, val)
27
- obj[key] = block ? @controller.instance_exec(@params.to_options, &block) : val
33
+ obj[key] = block ? @controller.instance_exec(params, &block) : val
28
34
  end
29
35
  end
30
36
 
31
37
  def dsl_block(key, val)
32
- swallow_nil { dsl_key(key)[val] }
38
+ swallow_nil { dsl_key(key)[val.to_s] }
33
39
  end
34
40
 
35
41
  def dsl_key(key)
36
- swallow_nil { @controller.class.dsls[key] }
42
+ swallow_nil { @controller.databound_config.read(:dsls)[key] }
37
43
  end
38
44
 
39
45
  def check_strict!(key, val)
@@ -45,7 +51,7 @@ module Databound
45
51
  end
46
52
 
47
53
  def strict?(key)
48
- swallow_nil { @controller.class.stricts[key] }
54
+ swallow_nil { @controller.databound_config.read(:stricts)[key] }
49
55
  end
50
56
  end
51
57
  end
@@ -1,5 +1,3 @@
1
- # module Databound
2
- # end
3
1
  def swallow_nil
4
2
  yield
5
3
  rescue NoMethodError
@@ -3,67 +3,78 @@ module Databound
3
3
  class Manager
4
4
  def initialize(controller)
5
5
  @controller = controller
6
- @model = @controller.send(:model)
7
6
 
8
- @scope = Databound::Data.new(controller, scope_js)
9
- @data = Databound::Data.new(controller, data_js).to_h
7
+ @scope = Databound::Data.new(@controller, scope_js, model)
8
+ @data = Databound::Data.new(@controller, data_js, model)
10
9
 
11
10
  @extra_where_scopes = JSON.parse(extra_where_scopes_js).map do |extra_scope|
12
- Databound::Data.new(controller, extra_scope)
11
+ Databound::Data.new(@controller, extra_scope, model)
13
12
  end
14
13
  end
15
14
 
16
15
  def find_scoped_records(only_extra_scopes: false)
17
- records = []
18
- records << @scope.records(@model)
16
+ records = model.where(or_query(@scope, *@extra_where_scopes))
17
+ records = filter_by_params!(records) unless only_extra_scopes
19
18
 
20
- @extra_where_scopes.each do |extra_scope|
21
- records << extra_scope.records(@model)
22
- end
23
-
24
- if only_extra_scopes
25
- records.flatten
26
- else
27
- records.map { |record| record.where(@data) }.flatten
28
- end
19
+ check_permit!(:read, params, records)
20
+ records
29
21
  end
30
22
 
31
23
  def create_from_data
32
- check_params!
33
- @model.where(@scope.to_h).create(@data)
24
+ check_params!(:create)
25
+ record = model.new(params.to_h)
26
+ check_permit!(:create, params, record)
27
+
28
+ record.save
29
+ record
34
30
  end
35
31
 
36
32
  def update_from_data
37
- id = @data.delete('id')
33
+ attributes = params.to_h
34
+ id = attributes.delete(:id)
38
35
 
39
- check_params!
40
- record = @model.find(id)
41
- check_permit_update_destroy!(record)
42
- record.update(@data)
36
+ check_params!(:update)
37
+ record = model.find(id)
38
+ check_permit!(:update, params, record)
43
39
 
40
+ record.update(attributes)
44
41
  record
45
42
  end
46
43
 
47
44
  def destroy_from_data
48
- record = @model.find(@data['id'])
49
- check_permit_update_destroy!(record)
45
+ record = model.find(params.id)
46
+ check_permit!(:destroy, params, record)
50
47
  record.destroy
51
48
  end
52
49
 
53
50
  private
54
51
 
55
- def check_params!
56
- return if permitted_columns == :all
52
+ def or_query(*scopes)
53
+ nodes = scopes.map do |scope|
54
+ model.where(scope.to_h).where_values.reduce(:and)
55
+ end
56
+
57
+ nodes[1..-1].reduce(nodes.first) do |memo, node|
58
+ node.or(memo)
59
+ end
60
+ end
61
+
62
+ def check_params!(action)
63
+ @action = action
64
+ return if columns == :all
57
65
  return if unpermitted_columns.empty?
58
66
 
59
67
  raise NotPermittedError, "Request includes unpermitted columns: #{unpermitted_columns.join(', ')}"
60
68
  end
61
69
 
62
- def check_permit_update_destroy!(record)
63
- return unless permit_update_destroy_block
64
- return if permit_update_destroy_block.call(record)
70
+ def check_permit!(method, params, record = nil)
71
+ permit_checks = @controller.databound_config.read(:permit)
72
+ check = permit_checks[method]
73
+
74
+ return unless check
75
+ return if @controller.instance_exec(params, record, &check)
65
76
 
66
- raise NotPermittedError, 'Request for update or destroy not permitted'
77
+ raise NotPermittedError, "Request for #{method} not permitted"
67
78
  end
68
79
 
69
80
  def permit_update_destroy_block
@@ -71,29 +82,35 @@ module Databound
71
82
  end
72
83
 
73
84
  def unpermitted_columns
74
- requested = [@scope, @data].map(&:to_h).flat_map(&:keys)
75
- requested - permitted_columns.map(&:to_s)
85
+ params.to_h.keys - columns - allowed_action_columns
76
86
  end
77
87
 
78
- def permitted_columns
79
- columns = @controller.send(:permitted_columns)
88
+ def params
89
+ OpenStruct.new(@scope.to_h.merge(@data.to_h))
90
+ end
91
+
92
+ def allowed_action_columns
93
+ @action == :update ? [:id] : []
94
+ end
80
95
 
81
- case columns
82
- when :all
96
+ def columns
97
+ result = @controller.databound_config.read(:columns)
98
+
99
+ case result
100
+ when [:all]
83
101
  :all
84
- when :table_columns
102
+ when [:table_columns]
85
103
  table_columns
86
104
  else
87
- Array(columns)
105
+ Array(result)
88
106
  end
89
107
  end
90
108
 
91
109
  def table_columns
92
- # permit all by default
93
110
  if mongoid?
94
111
  model.fields.keys.map(&:to_sym)
95
112
  elsif activerecord?
96
- model.column_names
113
+ model.column_names.map(&:to_sym)
97
114
  else
98
115
  raise 'ORM not supported. Use ActiveRecord or Mongoid'
99
116
  end
@@ -108,7 +125,13 @@ module Databound
108
125
  end
109
126
 
110
127
  def model
111
- @controller.send(:model)
128
+ raise 'No model specified' unless model_name
129
+
130
+ model_name.to_s.camelize.constantize
131
+ end
132
+
133
+ def model_name
134
+ @controller.databound_config.read(:model)
112
135
  end
113
136
 
114
137
  def scope_js
@@ -122,5 +145,13 @@ module Databound
122
145
  def extra_where_scopes_js
123
146
  @controller.params[:extra_where_scopes] || '[]'
124
147
  end
148
+
149
+ def extra_scope_records
150
+ @extra_where_scopes.flat_map(&:records)
151
+ end
152
+
153
+ def filter_by_params!(records)
154
+ records.where(params.to_h)
155
+ end
125
156
  end
126
157
  end
@@ -3,15 +3,16 @@ class ActionDispatch::Routing::Mapper
3
3
  namespace = @scope[:path]
4
4
  namespace = namespace[1..-1] if namespace
5
5
  opts = resources.pop if resources.last.is_a?(Hash)
6
+ Databound::Controller.add_application_controller_configs!
6
7
 
7
8
  resources.each do |resource|
8
9
  Rails.application.routes.draw do
9
- controller = [namespace, resource].compact.join('/')
10
- Databound::Utils.create_controller_unless_exists(controller, resource, opts)
10
+ controller_name = [namespace, resource].compact.join('/')
11
+ Databound::Controller.find_or_create(controller_name, resource, opts)
11
12
 
12
13
  %i(where create update destroy).each do |name|
13
14
  path = [namespace, resource, name].compact.join('/')
14
- to = [controller, name].join('#')
15
+ to = [controller_name, name].join('#')
15
16
  post path => to
16
17
  end
17
18
  end
@@ -1,3 +1,3 @@
1
1
  module Databound
2
- VERSION = '2.0.1'
2
+ VERSION = '3.0.0'
3
3
  end
@@ -1,6 +1,35 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe PermittedColumnsController, type: :controller do
3
+ describe PostsController, type: :controller do
4
+ describe 'via routes' do
5
+ it 'raise when param is not permitted' do
6
+ data = {
7
+ data: {
8
+ city: 'Barcelona',
9
+ },
10
+ scope: {},
11
+ }
12
+
13
+ expect { post(:create, javascriptize(data)) }.to raise_error(
14
+ Databound::NotPermittedError,
15
+ 'Request includes unpermitted columns: city',
16
+ )
17
+ end
18
+
19
+ it 'should create when param is permitted' do
20
+ data = {
21
+ data: {
22
+ title: 'Nikki',
23
+ },
24
+ scope: {},
25
+ }
26
+
27
+ expect { post(:create, javascriptize(data)) }.not_to raise_error
28
+ end
29
+ end
30
+ end
31
+
32
+ describe ColumnsController, type: :controller do
4
33
  describe '#create' do
5
34
  it 'raise when param is not permitted' do
6
35
  data = {
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe ProjectsController do
4
+ describe 'via routes' do
5
+ it 'should be able to specify model via routes' do
6
+ expect(ProjectsController.new.databound_config.read(:model)).to equal(:user)
7
+ end
8
+
9
+ it 'should be able to specify columns via routes' do
10
+ expect(ProjectsController.new.databound_config.read(:columns))
11
+ .to eql(%i(city user_id))
12
+ end
13
+ end
14
+ end
15
+
16
+ describe NoModelController, type: :controller do
17
+ describe 'raise error' do
18
+ it 'when model is not defined' do
19
+ expect { post(:create) }.to raise_error(RuntimeError)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe PermitController, type: :controller do
4
+ CURRENT_USER_ID = 1
5
+
6
+ before :each do
7
+ Project.create(city: 'LA', user_id: 5)
8
+ Project.create(city: 'LA', user_id: 1)
9
+ end
10
+
11
+ describe '#read' do
12
+ it 'raise when scope is not permitted' do
13
+ data = {
14
+ data: {
15
+ city: 'LA',
16
+ dont_permit: true,
17
+ },
18
+ scope: {},
19
+ }
20
+
21
+ expect { post(:where, javascriptize(data)) }.to raise_error(
22
+ Databound::NotPermittedError,
23
+ 'Request for read not permitted',
24
+ )
25
+ end
26
+
27
+ it 'should update when param is permitted' do
28
+ data = {
29
+ data: {
30
+ city: 'Barcelona',
31
+ user_id: 1,
32
+ },
33
+ scope: {},
34
+ }
35
+
36
+ expect { post(:where, javascriptize(data)) }.not_to raise_error
37
+ end
38
+ end
39
+
40
+ describe '#create' do
41
+ it 'raise when scope is not permitted' do
42
+ data = {
43
+ data: {
44
+ city: 'Barcelona',
45
+ user_id: 2,
46
+ },
47
+ scope: {},
48
+ }
49
+
50
+ expect { post(:create, javascriptize(data)) }.to raise_error(
51
+ Databound::NotPermittedError,
52
+ 'Request for create not permitted',
53
+ )
54
+ end
55
+
56
+ it 'should update when param is permitted' do
57
+ data = {
58
+ data: {
59
+ city: 'Barcelona',
60
+ user_id: 1,
61
+ },
62
+ scope: {},
63
+ }
64
+
65
+ expect { post(:create, javascriptize(data)) }.not_to raise_error
66
+ end
67
+ end
68
+
69
+ describe '#update' do
70
+ it 'raise when scope is not permitted' do
71
+ data = {
72
+ data: {
73
+ id: 1,
74
+ city: 'Barcelona',
75
+ },
76
+ scope: {},
77
+ }
78
+
79
+ expect { post(:update, javascriptize(data)) }.to raise_error(
80
+ Databound::NotPermittedError,
81
+ 'Request for update not permitted',
82
+ )
83
+ end
84
+
85
+ it 'should update when param is permitted' do
86
+ data = {
87
+ data: {
88
+ id: 2,
89
+ city: 'Barcelona',
90
+ },
91
+ scope: {},
92
+ }
93
+
94
+ expect { post(:update, javascriptize(data)) }.not_to raise_error
95
+ end
96
+ end
97
+
98
+ describe '#destroy' do
99
+ it 'raise when scope is not permitted' do
100
+ data = {
101
+ data: {
102
+ id: 1,
103
+ },
104
+ scope: {},
105
+ }
106
+
107
+ expect { post(:destroy, javascriptize(data)) }.to raise_error(
108
+ Databound::NotPermittedError,
109
+ 'Request for destroy not permitted',
110
+ )
111
+ end
112
+
113
+ it 'should destroy when param is permitted' do
114
+ data = {
115
+ data: {
116
+ id: 2,
117
+ },
118
+ scope: {},
119
+ }
120
+
121
+ expect { post(:destroy, javascriptize(data)) }.not_to raise_error
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,6 @@
1
+ class ColumnsController < ApplicationController
2
+ databound do
3
+ model :user
4
+ columns :name
5
+ end
6
+ end
@@ -1,21 +1,11 @@
1
1
  class DslController < ApplicationController
2
- include Databound
3
-
4
- private
5
-
6
- def model
7
- User
8
- end
9
-
10
- def permitted_columns
11
- %i(name city)
12
- end
13
-
14
- dsl(:city, :hottest) do
15
- 'Miami'
16
- end
17
-
18
- dsl(:city, :coldest) do |params|
19
- "Where #{params[:name]} lives"
2
+ databound do
3
+ model :user
4
+ columns :name, :city
5
+
6
+ dsl(:city, :hottest) { 'Miami' }
7
+ dsl(:city, :coldest) do |params|
8
+ "Where #{params.name} lives"
9
+ end
20
10
  end
21
11
  end
@@ -1,17 +1,8 @@
1
1
  class LooseDslController < ApplicationController
2
- include Databound
2
+ databound do
3
+ model :user
4
+ columns :name, :city
3
5
 
4
- private
5
-
6
- def permitted_columns
7
- %i(name city)
8
- end
9
-
10
- def model
11
- User
12
- end
13
-
14
- dsl(:city, :hottest, strict: false) do
15
- 'Miami'
6
+ dsl(:city, :hottest, strict: false) { 'Miami' }
16
7
  end
17
8
  end
@@ -1,3 +1,4 @@
1
1
  class NoModelController < ApplicationController
2
- include Databound
2
+ databound do
3
+ end
3
4
  end
@@ -0,0 +1,18 @@
1
+ class PermitController < ApplicationController
2
+ databound do
3
+ model :project
4
+ columns :name, :city, :user_id, :dont_permit
5
+
6
+ permit(:read) do |params, records|
7
+ !params.dont_permit
8
+ end
9
+
10
+ permit(:create) do |params|
11
+ params.user_id == CURRENT_USER_ID
12
+ end
13
+
14
+ permit(:update, :destroy) do |_, record|
15
+ record.user_id == CURRENT_USER_ID
16
+ end
17
+ end
18
+ end
@@ -1,13 +1,6 @@
1
1
  class UsersController < ApplicationController
2
- include Databound
3
-
4
- private
5
-
6
- def model
7
- User
8
- end
9
-
10
- def permitted_columns
11
- %i(name city)
2
+ databound do
3
+ model :user
4
+ columns :name, :city
12
5
  end
13
6
  end
@@ -1,10 +1,11 @@
1
1
  Rails.application.routes.draw do
2
2
  databound :users
3
3
  databound :no_model
4
- databound :permitted_columns
4
+ databound :columns
5
5
  databound :dsl
6
6
  databound :loose_dsl
7
- databound :messages, permitted_columns: :table_columns
8
- databound :permit_update_destroy
9
- databound :posts, permitted_columns: %i(title)
7
+ databound :messages, columns: :table_columns
8
+ databound :permit
9
+ databound :posts, columns: %i(title)
10
+ databound :projects, columns: %i(city user_id), model: :user
10
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: databound
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domas Bitvinskas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-04 00:00:00.000000000 Z
11
+ date: 2015-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-rails
@@ -122,7 +122,8 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '10.0'
125
- description: Works with ActiveRecord and Mongoid out of the box
125
+ description: It lets you use methods like create, update, destroy in the front-end
126
+ while handling all the setup and providing basic security out of the box.
126
127
  email:
127
128
  - domas.bitvinskas@me.com
128
129
  executables: []
@@ -138,29 +139,30 @@ files:
138
139
  - config.ru
139
140
  - databound.gemspec
140
141
  - lib/databound.rb
142
+ - lib/databound/config.rb
143
+ - lib/databound/controller.rb
141
144
  - lib/databound/data.rb
142
145
  - lib/databound/extensions.rb
143
146
  - lib/databound/manager.rb
144
147
  - lib/databound/rails/routes.rb
145
- - lib/databound/utils.rb
146
148
  - lib/databound/version.rb
147
149
  - lib/generators/databound/install/install_generator.rb
148
150
  - lib/generators/databound/install/templates/application.js
149
151
  - lib/generators/databound/install/templates/databound-standalone.js
152
+ - spec/controllers/columns_controller_spec.rb
150
153
  - spec/controllers/databound_spec.rb
151
154
  - spec/controllers/dsl_controller_spec.rb
152
155
  - spec/controllers/loose_dsl_controller_spec.rb
153
- - spec/controllers/no_model_controller_spec.rb
156
+ - spec/controllers/model_controller_spec.rb
154
157
  - spec/controllers/on_the_fly_spec.rb
155
- - spec/controllers/permit_update_destroy_controller_spec.rb
156
- - spec/controllers/permitted_columns_controller_spec.rb
157
- - spec/controllers/permitted_routes_columns_controller_spec.rb
158
+ - spec/controllers/permit_controller_spec.rb
159
+ - spec/controllers/routes_opts_controller_spec.rb
158
160
  - spec/internal/app/controllers/application_controller.rb
161
+ - spec/internal/app/controllers/columns_controller.rb
159
162
  - spec/internal/app/controllers/dsl_controller.rb
160
163
  - spec/internal/app/controllers/loose_dsl_controller.rb
161
164
  - spec/internal/app/controllers/no_model_controller.rb
162
- - spec/internal/app/controllers/permit_update_destroy_controller.rb
163
- - spec/internal/app/controllers/permitted_columns_controller.rb
165
+ - spec/internal/app/controllers/permit_controller.rb
164
166
  - spec/internal/app/controllers/users_controller.rb
165
167
  - spec/internal/app/models/message.rb
166
168
  - spec/internal/app/models/post.rb
@@ -222,7 +224,7 @@ files:
222
224
  - spec/support/rails_test_app/public/robots.txt
223
225
  - spec/support/rails_test_app/vendor/assets/javascripts/.keep
224
226
  - spec/support/rails_test_app/vendor/assets/stylesheets/.keep
225
- homepage: https://github.com/Nedomas/databound
227
+ homepage: http://databound.me
226
228
  licenses:
227
229
  - MIT
228
230
  metadata: {}
@@ -245,22 +247,22 @@ rubyforge_project:
245
247
  rubygems_version: 2.2.2
246
248
  signing_key:
247
249
  specification_version: 4
248
- summary: Databound exposes Ruby on Rails database to the Javascript side
250
+ summary: Provides Javascript a simple API to the Ruby on Rails CRUD
249
251
  test_files:
252
+ - spec/controllers/columns_controller_spec.rb
250
253
  - spec/controllers/databound_spec.rb
251
254
  - spec/controllers/dsl_controller_spec.rb
252
255
  - spec/controllers/loose_dsl_controller_spec.rb
253
- - spec/controllers/no_model_controller_spec.rb
256
+ - spec/controllers/model_controller_spec.rb
254
257
  - spec/controllers/on_the_fly_spec.rb
255
- - spec/controllers/permit_update_destroy_controller_spec.rb
256
- - spec/controllers/permitted_columns_controller_spec.rb
257
- - spec/controllers/permitted_routes_columns_controller_spec.rb
258
+ - spec/controllers/permit_controller_spec.rb
259
+ - spec/controllers/routes_opts_controller_spec.rb
258
260
  - spec/internal/app/controllers/application_controller.rb
261
+ - spec/internal/app/controllers/columns_controller.rb
259
262
  - spec/internal/app/controllers/dsl_controller.rb
260
263
  - spec/internal/app/controllers/loose_dsl_controller.rb
261
264
  - spec/internal/app/controllers/no_model_controller.rb
262
- - spec/internal/app/controllers/permit_update_destroy_controller.rb
263
- - spec/internal/app/controllers/permitted_columns_controller.rb
265
+ - spec/internal/app/controllers/permit_controller.rb
264
266
  - spec/internal/app/controllers/users_controller.rb
265
267
  - spec/internal/app/models/message.rb
266
268
  - spec/internal/app/models/post.rb
@@ -1,36 +0,0 @@
1
- module Databound
2
- class Utils
3
- def self.create_controller_unless_exists(path, resource, opts)
4
- return if exists?(path)
5
- opts ||= {}
6
-
7
- controller = Class.new(ApplicationController)
8
- controller.send(:include, Databound)
9
- controller.send(:define_method, :model) do
10
- resource.to_s.classify.constantize
11
- end
12
-
13
- controller.send(:define_method, :permitted_columns) do
14
- opts.fetch(:permitted_columns) do
15
- raise 'Specify permitted_columns in routes or the controller'
16
- end
17
- end
18
-
19
- Object.const_set(controller_name(path), controller)
20
- end
21
-
22
- def self.exists?(path)
23
- begin
24
- controller_name(path).constantize
25
- rescue NameError
26
- return false
27
- end
28
-
29
- true
30
- end
31
-
32
- def self.controller_name(path)
33
- "#{path.camelize}Controller"
34
- end
35
- end
36
- end
@@ -1,9 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe NoModelController, type: :controller do
4
- describe 'raise error' do
5
- it 'when model is not defined' do
6
- expect { post(:create) }.to raise_error(RuntimeError)
7
- end
8
- end
9
- end
@@ -1,66 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe PermitUpdateDestroyController, type: :controller do
4
- CURRENT_USER_ID = 1
5
-
6
- before :each do
7
- Project.create(city: 'LA', user_id: 5)
8
- Project.create(city: 'LA', user_id: 1)
9
- end
10
-
11
- describe '#update' do
12
- it 'raise when scope is not permitted' do
13
- data = {
14
- data: {
15
- id: 1,
16
- city: 'Barcelona',
17
- },
18
- scope: {},
19
- }
20
-
21
- expect { post(:update, javascriptize(data)) }.to raise_error(
22
- Databound::NotPermittedError,
23
- 'Request for update or destroy not permitted',
24
- )
25
- end
26
-
27
- it 'should update when param is permitted' do
28
- data = {
29
- data: {
30
- id: 2,
31
- city: 'Barcelona',
32
- },
33
- scope: {},
34
- }
35
-
36
- expect { post(:update, javascriptize(data)) }.not_to raise_error
37
- end
38
- end
39
-
40
- describe '#destroy' do
41
- it 'raise when scope is not permitted' do
42
- data = {
43
- data: {
44
- id: 1,
45
- },
46
- scope: {},
47
- }
48
-
49
- expect { post(:destroy, javascriptize(data)) }.to raise_error(
50
- Databound::NotPermittedError,
51
- 'Request for update or destroy not permitted',
52
- )
53
- end
54
-
55
- it 'should destroy when param is permitted' do
56
- data = {
57
- data: {
58
- id: 2,
59
- },
60
- scope: {},
61
- }
62
-
63
- expect { post(:destroy, javascriptize(data)) }.not_to raise_error
64
- end
65
- end
66
- end
@@ -1,17 +0,0 @@
1
- class PermitUpdateDestroyController < ApplicationController
2
- include Databound
3
-
4
- private
5
-
6
- def permitted_columns
7
- %i(name city)
8
- end
9
-
10
- def model
11
- Project
12
- end
13
-
14
- permit_update_destroy? do |record|
15
- record.user_id == CURRENT_USER_ID
16
- end
17
- end
@@ -1,13 +0,0 @@
1
- class PermittedColumnsController < ApplicationController
2
- include Databound
3
-
4
- private
5
-
6
- def model
7
- User
8
- end
9
-
10
- def permitted_columns
11
- %i(name)
12
- end
13
- end