zuul 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 38e3e0b42d2a30e697537fc0047a9c6b8a374b83
4
+ data.tar.gz: 7869d5ed786b1c1f8e65f4b97775ebc2d819b031
5
+ SHA512:
6
+ metadata.gz: 17e68b9709f5840e6a4087a078a93a42005c0a1ca49428916fe3ca28836110257680fee3232bf6a2be8c10437b950a1e203fadd180eb2f925f2a2082cd127ac3
7
+ data.tar.gz: 50fd987ea89c7444d83a71cd7275bf3955e265e55a0564aec01c1d0cee939403bce89a12a10bee4d8f38edf320598438b384cbcb1707c8549f03c4a9d31e5513
data/lib/zuul.rb CHANGED
@@ -8,6 +8,22 @@ module Zuul
8
8
  def self.configure(&block)
9
9
  @@configuration.configure &block
10
10
  end
11
+
12
+ def self.should_whitelist?
13
+ active_record3? or active_record4? && protected_attribtues?
14
+ end
15
+
16
+ def self.active_record3?
17
+ ::ActiveRecord::VERSION::MAJOR == 3
18
+ end
19
+
20
+ def self.active_record4?
21
+ ::ActiveRecord::VERSION::MAJOR == 4
22
+ end
23
+
24
+ def self.protected_attribtues?
25
+ defined? ::ProtectedAttributes
26
+ end
11
27
  end
12
28
 
13
29
  require 'zuul/context'
@@ -338,7 +338,8 @@ module Zuul
338
338
  # to provide easy access to the context for that object.
339
339
  module ContextMethods
340
340
  def self.included(base)
341
- base.send :attr_accessible, :context
341
+ base.send :attr_accessible, :context if ::Zuul
342
+ .should_whitelist?
342
343
  end
343
344
 
344
345
  # Return a Zuul::Context object representing the context for the role
@@ -9,7 +9,8 @@ module Zuul
9
9
 
10
10
  module ClassMethods
11
11
  def self.extended(base)
12
- base.send :attr_accessible, :context, :context_id, :context_type, :slug
12
+ base.send :attr_accessible, :context, :context_id, :context_type, :slug if ::Zuul
13
+ .should_whitelist?
13
14
  add_validations base
14
15
  add_associations base
15
16
  end
@@ -21,10 +22,10 @@ module Zuul
21
22
  end
22
23
 
23
24
  def self.add_associations(base)
24
- base.send :has_many, base.auth_scope.permission_roles_table_name.to_sym, :dependent => :destroy
25
- base.send :has_many, base.auth_scope.roles_table_name.to_sym, :through => base.auth_scope.permission_roles_table_name.to_sym
26
- base.send :has_many, base.auth_scope.permission_subjects_table_name.to_sym, :dependent => :destroy
27
- base.send :has_many, base.auth_scope.subjects_table_name.to_sym, :through => base.auth_scope.permission_subjects_table_name.to_sym
25
+ base.send :has_many, base.auth_scope.permission_role_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.permission_role_class_name, :dependent => :destroy
26
+ base.send :has_many, base.auth_scope.role_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.role_class_name, :through => base.auth_scope.permission_role_class_name.pluralize.underscore.to_sym
27
+ base.send :has_many, base.auth_scope.permission_subject_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.permission_subject_class_name, :dependent => :destroy
28
+ base.send :has_many, base.auth_scope.subject_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.subject_class_name, :through => base.auth_scope.permission_subject_class_name.pluralize.underscore.to_sym
28
29
  end
29
30
  end
30
31
 
@@ -37,14 +38,14 @@ module Zuul
37
38
  # Returns a list of contexts within which the permission has been assigned to roles
38
39
  def role_contexts
39
40
  auth_scope do
40
- send(permission_roles_table_name.to_sym).group(:context_type, :context_id).map(&:context)
41
+ send(permission_role_class_name.pluralize.underscore.to_sym).group(:context_type, :context_id).map(&:context)
41
42
  end
42
43
  end
43
44
 
44
45
  # Returns a list of contexts within which the permission has been assigned to subjects
45
46
  def subject_contexts
46
47
  auth_scope do
47
- send(permission_subjects_table_name.to_sym).group(:context_type, :context_id).map(&:context)
48
+ send(permission_subject_class_name.pluralize.underscore.to_sym).group(:context_type, :context_id).map(&:context)
48
49
  end
49
50
  end
50
51
  end
@@ -8,7 +8,8 @@ module Zuul
8
8
 
9
9
  module ClassMethods
10
10
  def self.extended(base)
11
- base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.role_foreign_key.to_sym
11
+ base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.role_foreign_key.to_sym if ::Zuul
12
+ .should_whitelist?
12
13
  add_validations base
13
14
  add_associations base
14
15
  end
@@ -20,8 +21,8 @@ module Zuul
20
21
  end
21
22
 
22
23
  def self.add_associations(base)
23
- base.send :belongs_to, base.auth_scope.permission_class_name.underscore.to_sym
24
- base.send :belongs_to, base.auth_scope.role_class_name.underscore.to_sym
24
+ base.send :belongs_to, base.auth_scope.permission_class_name.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.permission_class_name
25
+ base.send :belongs_to, base.auth_scope.role_class_name.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.role_class_name
25
26
  end
26
27
  end
27
28
  end
@@ -8,7 +8,8 @@ module Zuul
8
8
 
9
9
  module ClassMethods
10
10
  def self.extended(base)
11
- base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym
11
+ base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul
12
+ .should_whitelist?
12
13
  add_validations base
13
14
  add_associations base
14
15
  end
@@ -20,8 +21,8 @@ module Zuul
20
21
  end
21
22
 
22
23
  def self.add_associations(base)
23
- base.send :belongs_to, base.auth_scope.permission_class_name.underscore.to_sym
24
- base.send :belongs_to, base.auth_scope.subject_class_name.underscore.to_sym
24
+ base.send :belongs_to, base.auth_scope.permission_class_name.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.permission_class_name
25
+ base.send :belongs_to, base.auth_scope.subject_class_name.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.subject_class_name
25
26
  end
26
27
  end
27
28
  end
@@ -10,7 +10,8 @@ module Zuul
10
10
 
11
11
  module ClassMethods
12
12
  def self.extended(base)
13
- base.send :attr_accessible, :context_id, :context_type, :level, :slug
13
+ base.send :attr_accessible, :context_id, :context_type, :level, :slug if ::Zuul
14
+ .should_whitelist?
14
15
  add_validations base
15
16
  add_associations base
16
17
  end
@@ -24,11 +25,11 @@ module Zuul
24
25
  end
25
26
 
26
27
  def self.add_associations(base)
27
- base.send :has_many, base.auth_scope.role_subjects_table_name.to_sym, :dependent => :destroy
28
- base.send :has_many, base.auth_scope.subjects_table_name.to_sym, :through => base.auth_scope.role_subjects_table_name.to_sym
28
+ base.send :has_many, base.auth_scope.role_subject_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.role_subject_class_name, :dependent => :destroy
29
+ base.send :has_many, base.auth_scope.subject_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.subject_class_name, :through => base.auth_scope.role_subject_class_name.pluralize.underscore.to_sym
29
30
  if base.auth_scope.config.with_permissions
30
- base.send :has_many, base.auth_scope.permission_roles_table_name.to_sym, :dependent => :destroy
31
- base.send :has_many, base.auth_scope.permissions_table_name.to_sym, :through => base.auth_scope.permission_roles_table_name.to_sym
31
+ base.send :has_many, base.auth_scope.permission_role_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.permission_role_class_name, :dependent => :destroy
32
+ base.send :has_many, base.auth_scope.permission_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.permission_class_name, :through => base.auth_scope.permission_role_class_name.pluralize.underscore.to_sym
32
33
  end
33
34
  end
34
35
  end
@@ -37,7 +38,7 @@ module Zuul
37
38
  # Returns a list of contexts within which the role has been assigned to subjects
38
39
  def assigned_contexts
39
40
  auth_scope do
40
- send(role_subjects_table_name.to_sym).group(:context_type, :context_id).map(&:context)
41
+ send(role_subject_class_name.pluralize.underscore.to_sym).group(:context_type, :context_id).map(&:context)
41
42
  end
42
43
  end
43
44
  end
@@ -110,7 +111,7 @@ module Zuul
110
111
  force_context ||= config.force_context
111
112
  context = Zuul::Context.parse(context)
112
113
  if force_context
113
- return permission_class.joins(permission_roles_table_name.to_sym).where(permission_roles_table_name.to_sym => {role_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id})
114
+ return permission_class.joins(permission_role_class_name.pluralize.underscore.to_sym).where(permission_role_class_name.pluralize.underscore.to_sym => {role_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id})
114
115
  else
115
116
  return permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("#{permission_roles_table_name}.#{role_foreign_key} = ? AND (#{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_roles_table_name}.context_type IS NULL) AND (#{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_roles_table_name}.context_id IS NULL)", id, context.class_name, context.id)
116
117
  end
@@ -8,7 +8,8 @@ module Zuul
8
8
 
9
9
  module ClassMethods
10
10
  def self.extended(base)
11
- base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.role_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym
11
+ base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.role_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul
12
+ .should_whitelist?
12
13
  add_validations base
13
14
  add_associations base
14
15
  end
@@ -20,8 +21,8 @@ module Zuul
20
21
  end
21
22
 
22
23
  def self.add_associations(base)
23
- base.send :belongs_to, base.auth_scope.role_class_name.underscore.to_sym
24
- base.send :belongs_to, base.auth_scope.subject_class_name.underscore.to_sym
24
+ base.send :belongs_to, base.auth_scope.role_class_name.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.role_class_name
25
+ base.send :belongs_to, base.auth_scope.subject_class_name.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.subject_class_name
25
26
  end
26
27
  end
27
28
  end
@@ -14,8 +14,8 @@ module Zuul
14
14
 
15
15
  module ClassMethods
16
16
  def self.extended(base)
17
- base.send :has_many, base.auth_scope.role_subjects_table_name.to_sym, :dependent => :destroy
18
- base.send :has_many, base.auth_scope.roles_table_name.to_sym, :through => base.auth_scope.role_subjects_table_name.to_sym
17
+ base.send :has_many, base.auth_scope.role_subjects_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.role_subjects_class_name, :dependent => :destroy
18
+ base.send :has_many, base.auth_scope.roles_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.role_class_name, :through => base.auth_scope.role_subjects_class_name.underscore.to_sym.to_s.split("/").last.to_sym
19
19
  end
20
20
  end
21
21
 
@@ -113,9 +113,9 @@ module Zuul
113
113
  force_context ||= config.force_context
114
114
  context = Zuul::Context.parse(context)
115
115
  if force_context
116
- return role_class.joins(role_subjects_table_name.to_sym).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND #{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?", id, context.class_name, context.id)
116
+ return role_class.joins(role_subject_class_name.pluralize.underscore.to_sym).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND #{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?", id, context.class_name, context.id)
117
117
  else
118
- return role_class.joins(role_subjects_table_name.to_sym).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND ((#{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{role_subjects_table_name}.context_type IS NULL) AND (#{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{role_subjects_table_name}.context_id IS NULL))", id, context.class_name, context.id)
118
+ return role_class.joins(role_subject_class_name.pluralize.underscore.to_sym).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND ((#{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{role_subjects_table_name}.context_type IS NULL) AND (#{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{role_subjects_table_name}.context_id IS NULL))", id, context.class_name, context.id)
119
119
  end
120
120
  end
121
121
  end
@@ -137,8 +137,8 @@ module Zuul
137
137
 
138
138
  module ClassMethods
139
139
  def self.extended(base)
140
- base.send :has_many, base.auth_scope.permission_subjects_table_name.to_sym, :dependent => :destroy
141
- base.send :has_many, base.auth_scope.permissions_table_name.to_sym, :through => base.auth_scope.permission_subjects_table_name.to_sym
140
+ base.send :has_many, base.auth_scope.permission_subject_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.permission_subject_class_name, :dependent => :destroy
141
+ base.send :has_many, base.auth_scope.permission_class_name.pluralize.underscore.to_sym.to_s.split("/").last.to_sym, :class_name => base.auth_scope.permission_class_name, :through => base.auth_scope.permission_subject_class_name.pluralize.underscore.to_sym
142
142
  end
143
143
  end
144
144
 
data/lib/zuul/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Zuul
2
- VERSION = '0.2.4'
2
+ VERSION = '0.2.5'
3
3
  end
@@ -1,17 +1,20 @@
1
1
  # Default Subject, Role, Permission and Context models
2
2
  Object.send(:remove_const, :User) if defined?(User) # we do this to undefine the model and start fresh, without any of the authorization stuff applied by tests
3
3
  class User < ActiveRecord::Base
4
- attr_accessible :name
4
+ attr_accessible :name if ::Zuul
5
+ .should_whitelist?
5
6
  end
6
7
 
7
8
  Object.send(:remove_const, :Role) if defined?(Role)
8
9
  class Role < ActiveRecord::Base
9
- attr_accessible :name, :slug, :level, :context_type, :context_id
10
+ attr_accessible :name, :slug, :level, :context_type, :context_id if ::Zuul
11
+ .should_whitelist?
10
12
  end
11
13
 
12
14
  Object.send(:remove_const, :Permission) if defined?(Permission)
13
15
  class Permission < ActiveRecord::Base
14
- attr_accessible :name, :slug, :context_type, :context_id
16
+ attr_accessible :name, :slug, :context_type, :context_id if ::Zuul
17
+ .should_whitelist?
15
18
  end
16
19
 
17
20
  Object.send(:remove_const, :Context) if defined?(Context)
@@ -81,17 +84,20 @@ end
81
84
  # Custom named Subject, Role, Permission and Context models
82
85
  Object.send(:remove_const, :Soldier) if defined?(Soldier)
83
86
  class Soldier < ActiveRecord::Base
84
- attr_accessible :name
87
+ attr_accessible :name if ::Zuul
88
+ .should_whitelist?
85
89
  end
86
90
 
87
91
  Object.send(:remove_const, :Rank) if defined?(Rank)
88
92
  class Rank < ActiveRecord::Base
89
- attr_accessible :name, :slug, :level, :context_type, :context_id
93
+ attr_accessible :name, :slug, :level, :context_type, :context_id if ::Zuul
94
+ .should_whitelist?
90
95
  end
91
96
 
92
97
  Object.send(:remove_const, :Skill) if defined?(Skill)
93
98
  class Skill < ActiveRecord::Base
94
- attr_accessible :name, :slug, :context_type, :context_id
99
+ attr_accessible :name, :slug, :context_type, :context_id if ::Zuul
100
+ .should_whitelist?
95
101
  end
96
102
 
97
103
  Object.send(:remove_const, :Weapon) if defined?(Weapon)
@@ -130,17 +136,20 @@ module ZuulModels
130
136
 
131
137
  send(:remove_const, :User) if defined?(ZuulModels::User)
132
138
  class User < ActiveRecord::Base
133
- attr_accessible :name
139
+ attr_accessible :name if ::Zuul
140
+ .should_whitelist?
134
141
  end
135
142
 
136
143
  send(:remove_const, :Role) if defined?(ZuulModels::Role)
137
144
  class Role < ActiveRecord::Base
138
- attr_accessible :name, :slug, :level, :context_type, :context_id
145
+ attr_accessible :name, :slug, :level, :context_type, :context_id if ::Zuul
146
+ .should_whitelist?
139
147
  end
140
148
 
141
149
  send(:remove_const, :Permission) if defined?(ZuulModels::Permission)
142
150
  class Permission < ActiveRecord::Base
143
- attr_accessible :name, :slug, :context_type, :context_id
151
+ attr_accessible :name, :slug, :context_type, :context_id if ::Zuul
152
+ .should_whitelist?
144
153
  end
145
154
 
146
155
  send(:remove_const, :Context) if defined?(ZuulModels::Context)
metadata CHANGED
@@ -1,94 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zuul
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
5
- prerelease:
4
+ version: 0.2.5
6
5
  platform: ruby
7
6
  authors:
8
7
  - Mark Rebec
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-05-02 00:00:00.000000000 Z
11
+ date: 2013-06-03 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activesupport
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: activerecord
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: actionpack
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: sqlite3
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - '>='
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - '>='
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rspec
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - '>='
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - '>='
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  description: Flexible, configurable authorization system for ActiveRecord and an access
@@ -157,27 +146,26 @@ files:
157
146
  - spec/spec_helper.rb
158
147
  homepage: http://github.com/markrebec/zuul
159
148
  licenses: []
149
+ metadata: {}
160
150
  post_install_message:
161
151
  rdoc_options: []
162
152
  require_paths:
163
153
  - lib
164
154
  required_ruby_version: !ruby/object:Gem::Requirement
165
- none: false
166
155
  requirements:
167
- - - ! '>='
156
+ - - '>='
168
157
  - !ruby/object:Gem::Version
169
158
  version: '0'
170
159
  required_rubygems_version: !ruby/object:Gem::Requirement
171
- none: false
172
160
  requirements:
173
- - - ! '>='
161
+ - - '>='
174
162
  - !ruby/object:Gem::Version
175
163
  version: '0'
176
164
  requirements: []
177
165
  rubyforge_project:
178
- rubygems_version: 1.8.25
166
+ rubygems_version: 2.0.0.rc.2
179
167
  signing_key:
180
- specification_version: 3
168
+ specification_version: 4
181
169
  summary: Authorizaion and ACL for Activerecord and ActionController.
182
170
  test_files:
183
171
  - spec/db/schema.rb