attr_accessible_block 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "activerecord", ">= 2.3.5"
4
+
5
+ group :development do
6
+ gem "shoulda", ">= 0"
7
+ gem "bundler", "~> 1.0.0"
8
+ gem "jeweler", "~> 1.5.2"
9
+ gem 'sqlite3-ruby', '~> 1.3.2'
10
+ gem "rcov", ">= 0"
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,37 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.0.3)
5
+ activesupport (= 3.0.3)
6
+ builder (~> 2.1.2)
7
+ i18n (~> 0.4)
8
+ activerecord (3.0.3)
9
+ activemodel (= 3.0.3)
10
+ activesupport (= 3.0.3)
11
+ arel (~> 2.0.2)
12
+ tzinfo (~> 0.3.23)
13
+ activesupport (3.0.3)
14
+ arel (2.0.6)
15
+ builder (2.1.2)
16
+ git (1.2.5)
17
+ i18n (0.5.0)
18
+ jeweler (1.5.2)
19
+ bundler (~> 1.0.0)
20
+ git (>= 1.2.5)
21
+ rake
22
+ rake (0.8.7)
23
+ rcov (0.9.9)
24
+ shoulda (2.11.3)
25
+ sqlite3-ruby (1.3.2)
26
+ tzinfo (0.3.23)
27
+
28
+ PLATFORMS
29
+ ruby
30
+
31
+ DEPENDENCIES
32
+ activerecord (>= 2.3.5)
33
+ bundler (~> 1.0.0)
34
+ jeweler (~> 1.5.2)
35
+ rcov
36
+ shoulda
37
+ sqlite3-ruby (~> 1.3.2)
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,94 @@
1
+ AttrAccessibleBlock 0.2
2
+ =======================
3
+
4
+ This is an ActiveRecord plugin with possibility to define block inside the `attr_accessible` class method.
5
+
6
+ Tested with Rails 2.3 and 3.0
7
+
8
+ Because of block, it's possible to define accessibles for instances, nor just for the class level.
9
+
10
+ It's also still possible to define class level accessibles, so an old `attr_accessible :name` will work.
11
+
12
+ Main features:
13
+
14
+ * Possibility to add an accessible attributes based on current `record` state (eg. record.new_record?)
15
+ * Possibility to add additional variables and use it in the block (eg. user.role) `ActiveRecord::AttrAccessibleBlock.before_options :user, lambda { User.current || User.new }`
16
+ * Possibility to add permanently total accessibility in defined condition (eg.user.admin?) `ActiveRecord::AttrAccessibleBlock.always_accessible { user.admin? }`
17
+
18
+ Also it's possible to check directly is attribute mass-assignable or no using `attr_accessible?` instance method.
19
+
20
+ See an examples to understand the conception.
21
+
22
+ Installation
23
+ ============
24
+
25
+ script/plugin install git://github.com//dmitry/attr_accessible_block.git
26
+
27
+ Examples
28
+ ========
29
+
30
+ How many times you had code like that:
31
+
32
+ class User < ActiveRecord::Base
33
+ attr_accessible :password, :password_confirmation
34
+
35
+ # ...
36
+ end
37
+
38
+ And in controller:
39
+
40
+ def create
41
+ user = User.new(params[:user])
42
+ user.email = params[:user][:email]
43
+ user.save
44
+
45
+ # ...
46
+ end
47
+
48
+ Now it's possible to do it easier:
49
+
50
+ class User < ActiveRecord::Base
51
+ attr_accessible do
52
+ self << [:password, :password_confirmation]
53
+ self << :email if record.new_record?
54
+ end
55
+ end
56
+
57
+ And creation of the user now can be written more DRYer
58
+
59
+ user = User.create(params[:user])
60
+
61
+ And on user update changing of email will be rejected because of `new_record?` method.
62
+
63
+ Sometimes you may need to check is attribute of model assignable or no (this method mostly interesting when doing form inputs). You can do it with using `attr_accessible?` method:
64
+
65
+ user.assignable?(:email) # returns false
66
+ user.assignable?(:password) # returns true
67
+
68
+ How do I add something similar to `record`, for example I want to check current users role?
69
+
70
+ Easy, with `sentient_user` gem and add the code to the `config/initializers/plugins.rb` file:
71
+
72
+ ActiveRecord::AttrAccessibleBlock.before_options :user, lambda { User.current || User.new }
73
+
74
+ Now `user` method available, you can check:
75
+
76
+ attr_accessible do
77
+ self << [:password, :password_confirmation]
78
+ self << :email if record.new_record? || user.manager?
79
+ self << [:some_secret_fields, :another] if user.manager?
80
+ end
81
+
82
+ What if I want to provide an total accessibility for the admin user?
83
+
84
+ Just add this code to the `config/initializers/plugins.rb` file:
85
+
86
+ ActiveRecord::AttrAccessibleBlock.always_accessible { user.admin? }
87
+
88
+ NOTICE: when using attr_accessible as a block, then no second parameter is available for the `attributes=` method (guard_protected_attributes = true). Instead use power of blocks! Also do not use attr_protected, because it's bad :)
89
+
90
+ Should be STI compatible, but haven't tested yet. Need's feedback on this feature. Feel free to contact with me if something goes wrong.
91
+
92
+ For more answers on your questions you can look into tests and source code.
93
+
94
+ Copyright (c) 2010 Dmitry Polushkin, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,50 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ gem.name = "attr_accessible_block"
15
+ gem.homepage = "http://github.com/dmitry/attr_accessible_block"
16
+ gem.license = "MIT"
17
+ gem.summary = %Q{Attribute accessible block (attr_accessible with a block, dynamic)}
18
+ gem.description = %Q{Now it's possible to change attr_accessible using definition of the required accessible attributes in a block.}
19
+ gem.email = "dmitry.polushkin@gmail.com"
20
+ gem.authors = ["Dmitry Polushkin"]
21
+ gem.version = '0.2.0'
22
+ gem.add_runtime_dependency 'activerecord', '>= 2.3.5'
23
+ end
24
+ Jeweler::RubygemsDotOrgTasks.new
25
+
26
+ require 'rake/testtask'
27
+ Rake::TestTask.new(:test) do |test|
28
+ test.libs << 'lib' << 'test'
29
+ test.pattern = 'test/**/test_*.rb'
30
+ test.verbose = true
31
+ end
32
+
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/test_*.rb'
37
+ test.verbose = true
38
+ end
39
+
40
+ task :default => :test
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
45
+
46
+ rdoc.rdoc_dir = 'rdoc'
47
+ rdoc.title = "attr_accessible_block #{version}"
48
+ rdoc.rdoc_files.include('README*')
49
+ rdoc.rdoc_files.include('lib/**/*.rb')
50
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'attr_accessible_block'
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,73 @@
1
+ class ActiveRecord::Base
2
+ class << self
3
+ alias_method :old_attr_accessible, :attr_accessible
4
+ end
5
+ def self.attr_accessible(*attributes, &block)
6
+ if block_given?
7
+ write_inheritable_attribute(:attr_accessible_block, block)
8
+ self.superclass.send :alias_method, :old_attributes=, :attributes=
9
+ define_method :attributes= do |attrs|
10
+ ActiveRecord::AttrAccessibleBlock.new(attrs, self, &block)
11
+
12
+ send(:old_attributes=, attrs)
13
+ end
14
+ else
15
+ old_attr_accessible(*attributes)
16
+ end
17
+ end
18
+
19
+ def attr_accessible?(attribute)
20
+ klass = self.class
21
+ block = klass.read_inheritable_attribute(:attr_accessible_block)
22
+ if block
23
+ attributes = {attribute => nil}
24
+ ActiveRecord::AttrAccessibleBlock.new(attributes, self, &block)
25
+ attributes.has_key?(attribute)
26
+ else
27
+ # rails 2/3 compatibility
28
+ if klass.respond_to?(:accessible_attributes)
29
+ klass.accessible_attributes.include?(attribute.to_s)
30
+ else
31
+ klass._accessible_attributes.include?(attribute)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+
38
+ class ActiveRecord::AttrAccessibleBlock < Array
39
+ attr_reader :attrs, :record
40
+
41
+ def initialize(attrs, record, &block)
42
+ @attrs = attrs
43
+
44
+ @@before_options.each do |name, func|
45
+ instance_variable_set("@#{name}", func.call)
46
+ end
47
+
48
+ @record = record
49
+
50
+ unless instance_eval(&@@always_accessible)
51
+ instance_eval(&block)
52
+
53
+ flatten!
54
+ reject_attrs!
55
+ end
56
+ end
57
+
58
+ def self.before_options(name, func)
59
+ @@before_options ||= {}
60
+ @@before_options[name] = func
61
+ attr_reader name
62
+ end
63
+
64
+ def self.always_accessible(&block)
65
+ @@always_accessible = block
66
+ end
67
+
68
+ private
69
+
70
+ def reject_attrs!
71
+ @attrs.reject! { |k,v| !self.include?(k.to_sym) }
72
+ end
73
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :attr_accessible_block do
3
+ # # Task goes here
4
+ # end
data/test/schema.rb ADDED
@@ -0,0 +1,58 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :users, :force => true do |t|
3
+ t.string :email, :null => false
4
+ t.string :password, :null => false
5
+ t.string :role, :null => false
6
+ end
7
+
8
+ create_table :profiles, :force => true do |t|
9
+ t.references :user, :null => false
10
+ t.string :first_name, :null => false
11
+ t.string :last_name, :null => false
12
+ end
13
+
14
+ create_table :locations, :force => true do |t|
15
+ t.string :name, :null => false
16
+ t.string :code, :null => false
17
+ end
18
+ end
19
+
20
+ class User < ActiveRecord::Base
21
+ attr_accessible do
22
+ self << [:password, :profile_attributes]
23
+ self << :email if record.new_record? || 'manager' == user.role
24
+ end
25
+
26
+ has_one :profile
27
+ accepts_nested_attributes_for :profile
28
+
29
+ before_create :set_default_role
30
+
31
+ validates_presence_of :email, :password
32
+
33
+ def self.current
34
+ User.last
35
+ end
36
+
37
+ private
38
+
39
+ def set_default_role
40
+ self.role ||= 'default'
41
+ end
42
+ end
43
+
44
+ class Profile < ActiveRecord::Base
45
+ attr_accessible do
46
+ self << [:first_name, :last_name] if record.new_record?
47
+ end
48
+
49
+ belongs_to :user
50
+
51
+ validates_presence_of :first_name, :last_name
52
+ end
53
+
54
+ class Location < ActiveRecord::Base
55
+ attr_accessible :name
56
+
57
+ validates_presence_of :name, :code
58
+ end
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+
3
+ ActiveRecord::AttrAccessibleBlock.before_options :user, lambda { User.current || User.new }
4
+ ActiveRecord::AttrAccessibleBlock.always_accessible { 'admin' == user.role }
5
+
6
+ class AttrAccessibleBlockTest < Test::Unit::TestCase
7
+ def setup
8
+ setup_db
9
+
10
+ [User, Profile].each do |k|
11
+ k.delete_all
12
+ end
13
+ end
14
+
15
+ def teardown
16
+ teardown_db
17
+ end
18
+
19
+ def test_should_reject
20
+ user = User.create(:email => 'test@test.com', :password => 'test', :role => 'admin')
21
+ assert user.valid?
22
+ assert !user.new_record?
23
+ assert_equal 'test', user.password
24
+ assert_equal 'test@test.com', user.email
25
+ assert_equal 'default', user.role
26
+ end
27
+
28
+ def test_should_always_accessible
29
+ user = User.new(:email => 'test@test.com', :password => 'test', :profile_attributes => {:first_name => 'first name', :last_name => 'last name'})
30
+ user.role = 'admin'
31
+ assert user.save
32
+ assert !user.profile.new_record?
33
+ assert_equal 'admin', user.role
34
+ assert_equal 'first name', user.profile.first_name
35
+ assert user.update_attributes(:profile_attributes => {:id => user.profile.id, :first_name => 'first'})
36
+ assert_equal 'first', user.profile.first_name
37
+ end
38
+
39
+ def test_should_change_only_on_create
40
+ user = User.create(:email => 'test@test.com', :password => 'test')
41
+ assert user.update_attributes(:email => 'new@new.com')
42
+ assert_equal 'test@test.com', user.email
43
+ end
44
+
45
+ def test_should_work_attr_accessible_question_with_block
46
+ user = User.new(:email => 'test@test.com', :password => 'test')
47
+ assert_equal true, user.attr_accessible?(:email)
48
+ assert_equal true, user.attr_accessible?(:password)
49
+ user.save
50
+ assert_equal false, user.attr_accessible?(:email)
51
+ assert_equal true, user.attr_accessible?(:password)
52
+ end
53
+
54
+ def test_should_work_attr_accessible_question_without_block
55
+ l = Location.new(:name => 'name', :code => 'code')
56
+ assert_equal true, l.attr_accessible?(:name)
57
+ assert_equal false, l.attr_accessible?(:code)
58
+ end
59
+
60
+ def test_should_access_to_before_options_reader
61
+ user = User.new(:email => 'test@test.com', :password => 'test', :profile_attributes => {:first_name => 'first name', :last_name => 'last name'})
62
+ user.role = 'manager'
63
+ assert user.save
64
+ user.attributes = {:email => 'new@new.com'}
65
+ assert user.save
66
+ assert_equal 'new@new.com', user.email
67
+ end
68
+
69
+ def test_simple_attr_accessible_should_work_as_expected
70
+ l = Location.create(:name => 'name', :code => 'code')
71
+ assert !l.valid?
72
+ assert_equal 'name', l.name
73
+ assert_equal nil, l.code
74
+ l.update_attribute(:code, 'code')
75
+ assert l.valid?
76
+ assert_equal 'code', l.code
77
+ l.code = 'changed'
78
+ l.save
79
+ assert l.valid?
80
+ assert_equal 'changed', l.code
81
+ end
82
+ end
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ gem 'activerecord', '~> 3.0'
5
+
6
+ require 'active_support'
7
+ require 'active_record'
8
+ require 'logger'
9
+
10
+ require 'attr_accessible_block'
11
+
12
+ ActiveRecord::Base.logger = Logger.new("test.log")
13
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
14
+
15
+ def setup_db
16
+ ActiveRecord::Migration.verbose = false
17
+ load "schema.rb"
18
+ end
19
+
20
+ def teardown_db
21
+ ActiveRecord::Base.connection.tables.each do |table|
22
+ ActiveRecord::Base.connection.drop_table(table)
23
+ end
24
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attr_accessible_block
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Dmitry Polushkin
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-16 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 9
30
+ segments:
31
+ - 2
32
+ - 3
33
+ - 5
34
+ version: 2.3.5
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: shoulda
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: bundler
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 23
60
+ segments:
61
+ - 1
62
+ - 0
63
+ - 0
64
+ version: 1.0.0
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: jeweler
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ hash: 7
76
+ segments:
77
+ - 1
78
+ - 5
79
+ - 2
80
+ version: 1.5.2
81
+ type: :development
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3-ruby
85
+ prerelease: false
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ~>
90
+ - !ruby/object:Gem::Version
91
+ hash: 31
92
+ segments:
93
+ - 1
94
+ - 3
95
+ - 2
96
+ version: 1.3.2
97
+ type: :development
98
+ version_requirements: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ name: rcov
101
+ prerelease: false
102
+ requirement: &id006 !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ type: :development
112
+ version_requirements: *id006
113
+ - !ruby/object:Gem::Dependency
114
+ name: activerecord
115
+ prerelease: false
116
+ requirement: &id007 !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ hash: 9
122
+ segments:
123
+ - 2
124
+ - 3
125
+ - 5
126
+ version: 2.3.5
127
+ type: :runtime
128
+ version_requirements: *id007
129
+ description: Now it's possible to change attr_accessible using definition of the required accessible attributes in a block.
130
+ email: dmitry.polushkin@gmail.com
131
+ executables: []
132
+
133
+ extensions: []
134
+
135
+ extra_rdoc_files:
136
+ - README.md
137
+ files:
138
+ - Gemfile
139
+ - Gemfile.lock
140
+ - MIT-LICENSE
141
+ - README.md
142
+ - Rakefile
143
+ - init.rb
144
+ - install.rb
145
+ - lib/attr_accessible_block.rb
146
+ - tasks/attr_accessible_block_tasks.rake
147
+ - test/schema.rb
148
+ - test/test_attr_accessible_block.rb
149
+ - test/test_helper.rb
150
+ - uninstall.rb
151
+ has_rdoc: true
152
+ homepage: http://github.com/dmitry/attr_accessible_block
153
+ licenses:
154
+ - MIT
155
+ post_install_message:
156
+ rdoc_options: []
157
+
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ hash: 3
166
+ segments:
167
+ - 0
168
+ version: "0"
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ hash: 3
175
+ segments:
176
+ - 0
177
+ version: "0"
178
+ requirements: []
179
+
180
+ rubyforge_project:
181
+ rubygems_version: 1.3.7
182
+ signing_key:
183
+ specification_version: 3
184
+ summary: Attribute accessible block (attr_accessible with a block, dynamic)
185
+ test_files:
186
+ - test/schema.rb
187
+ - test/test_attr_accessible_block.rb
188
+ - test/test_helper.rb