hobo 2.0.1 → 2.1.0.pre1
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 +7 -0
- data/CHANGES-2.1.markdown +57 -0
- data/Gemfile +1 -1
- data/VERSION +1 -1
- data/app/helpers/hobo_permissions_helper.rb +1 -1
- data/app/helpers/hobo_route_helper.rb +10 -79
- data/config/routes.rb +2 -2
- data/hobo.gemspec +1 -1
- data/lib/generators/hobo/admin_subsite/admin_subsite_generator.rb +3 -1
- data/lib/generators/hobo/controller.rb +4 -1
- data/lib/generators/hobo/front_controller/front_controller_generator.rb +7 -6
- data/lib/generators/hobo/i18n/templates/hobo.en.yml +2 -1
- data/lib/generators/hobo/i18n/templates/hobo.es.yml +1 -0
- data/lib/generators/hobo/i18n/templates/hobo.ru.yml +1 -0
- data/lib/generators/hobo/routes/router.rb +5 -3
- data/lib/generators/hobo/routes/templates/hobo_routes.rb.erb +0 -36
- data/lib/generators/hobo/setup_wizard/setup_wizard_generator.rb +2 -2
- data/lib/hobo.rb +2 -2
- data/lib/hobo/controller.rb +1 -1
- data/lib/hobo/controller/model.rb +4 -4
- data/lib/hobo/extensions/active_record/associations/association.rb +1 -1
- data/lib/hobo/extensions/active_record/associations/scope.rb +6 -5
- data/lib/hobo/extensions/active_record/relation_with_origin.rb +9 -7
- data/lib/hobo/model.rb +1 -2
- data/lib/hobo/model/accessible_associations.rb +4 -5
- data/lib/hobo/model/permissions.rb +7 -6
- data/lib/hobo/model/scopes.rb +1 -3
- data/lib/hobo/model/scopes/apply_scopes.rb +3 -3
- data/test/irt/generators/admin_subsite.irt +6 -0
- metadata +17 -39
- data/test/doctest/hobo/multi_model_forms.rdoctest +0 -260
- data/test/doctest/hobo/scopes.rdoctest +0 -375
@@ -24,7 +24,7 @@ module ActiveRecord
|
|
24
24
|
|
25
25
|
private
|
26
26
|
|
27
|
-
def raise_on_type_mismatch(record)
|
27
|
+
def raise_on_type_mismatch!(record)
|
28
28
|
# Don't complain if the interface type of a polymorphic association doesn't exist
|
29
29
|
klass = @reflection.klass rescue nil
|
30
30
|
unless klass.nil? || record.is_a?(klass)
|
@@ -14,9 +14,10 @@ module ActiveRecord
|
|
14
14
|
end
|
15
15
|
end if false # DISABLED Getting Rails 3.1 working
|
16
16
|
|
17
|
-
|
17
|
+
class Relation
|
18
|
+
module DeprecatedMethods
|
18
19
|
|
19
|
-
def apply_finder_options_with_scope(options)
|
20
|
+
def apply_finder_options_with_scope(options, silence_deprecation = false)
|
20
21
|
scopes = []
|
21
22
|
Array.wrap(options.delete(:scope)).each do |s|
|
22
23
|
if s.is_a?(Hash)
|
@@ -25,11 +26,11 @@ module ActiveRecord
|
|
25
26
|
scopes << [s]
|
26
27
|
end
|
27
28
|
end
|
28
|
-
relation = apply_finder_options_without_scope(options)
|
29
|
+
relation = apply_finder_options_without_scope(options, silence_deprecation)
|
29
30
|
return relation if scopes.empty?
|
30
31
|
scopes.inject(relation) {|r, s| r.send *s }
|
31
32
|
end
|
32
33
|
alias_method_chain :apply_finder_options, :scope
|
33
|
-
|
34
|
-
|
34
|
+
end if false # DISABLED Getting Rails 4.0 working
|
35
|
+
end
|
35
36
|
end
|
@@ -24,13 +24,15 @@ module ActiveRecord
|
|
24
24
|
module Associations
|
25
25
|
class CollectionProxy
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
# FIXME Ralis4: really hoping that we can replace this with
|
28
|
+
# something based on https://github.com/rails/rails/issues/5717
|
29
|
+
# def scoped_with_origin
|
30
|
+
# relation = scoped_without_origin.clone
|
31
|
+
# relation.origin = proxy_association.owner
|
32
|
+
# relation.origin_attribute = proxy_association.reflection.name
|
33
|
+
# relation
|
34
|
+
# end
|
35
|
+
# alias_method_chain :scoped, :origin
|
34
36
|
|
35
37
|
def method_missing_with_origin(method, *args, &block)
|
36
38
|
res = method_missing_without_origin(method, *args, &block)
|
data/lib/hobo/model.rb
CHANGED
@@ -227,7 +227,6 @@ module Hobo
|
|
227
227
|
|
228
228
|
def find_by_sql(*args)
|
229
229
|
result = super
|
230
|
-
result.member_class = self # find_by_sql always returns array
|
231
230
|
result
|
232
231
|
end
|
233
232
|
|
@@ -278,7 +277,7 @@ module Hobo
|
|
278
277
|
r.klass >= self &&
|
279
278
|
!r.options[:conditions] &&
|
280
279
|
!r.options[:scope] &&
|
281
|
-
r.foreign_key == refl.foreign_key
|
280
|
+
r.foreign_key.to_s == refl.foreign_key.to_s
|
282
281
|
end
|
283
282
|
end
|
284
283
|
end
|
@@ -11,7 +11,7 @@ module Hobo
|
|
11
11
|
array.map! do |record_hash_or_string|
|
12
12
|
finder = association.member_class
|
13
13
|
conditions = association.proxy_association.reflection.options[:conditions]
|
14
|
-
finder = finder.
|
14
|
+
finder = finder.where(conditions) unless conditions == [[]] || conditions == [[],[]]
|
15
15
|
find_or_create_and_update(owner, association_name, finder, record_hash_or_string) do |id|
|
16
16
|
# The block is required to either locate find an existing record in the collection, or build a new one
|
17
17
|
if id
|
@@ -91,7 +91,8 @@ module Hobo
|
|
91
91
|
|
92
92
|
def finder_for_belongs_to(record, name)
|
93
93
|
refl = record.class.reflections[name]
|
94
|
-
conditions = ActiveRecord::Associations::BelongsToAssociation.new(record, refl).reflection.send(:conditions)
|
94
|
+
#conditions = ActiveRecord::Associations::BelongsToAssociation.new(record, refl).reflection.send(:conditions)
|
95
|
+
conditions = [[]]
|
95
96
|
conditions == [[]] || conditions == [[],[]] ? refl.klass : refl.klass.scoped(:conditions => conditions)
|
96
97
|
end
|
97
98
|
|
@@ -104,7 +105,6 @@ module Hobo
|
|
104
105
|
|
105
106
|
def self.has_many_with_accessible(name, options={}, &block)
|
106
107
|
has_many_without_accessible(name, options, &block)
|
107
|
-
|
108
108
|
if options[:accessible]
|
109
109
|
class_eval %{
|
110
110
|
def #{name}_with_accessible=(array_or_hash)
|
@@ -163,8 +163,7 @@ module Hobo
|
|
163
163
|
|
164
164
|
|
165
165
|
# Add :accessible to the valid options so AR doesn't complain
|
166
|
-
::ActiveRecord::Associations::Builder::
|
167
|
-
::ActiveRecord::Associations::Builder::HasMany.valid_options << :accessible
|
166
|
+
::ActiveRecord::Associations::Builder::Association.valid_options << :accessible
|
168
167
|
|
169
168
|
end
|
170
169
|
end
|
@@ -7,8 +7,8 @@ module Hobo
|
|
7
7
|
klass.class_eval do
|
8
8
|
extend ClassMethods
|
9
9
|
|
10
|
-
alias_method_chain :
|
11
|
-
alias_method_chain :
|
10
|
+
alias_method_chain :create_record, :hobo_permission_check
|
11
|
+
alias_method_chain :update_record, :hobo_permission_check
|
12
12
|
alias_method_chain :destroy, :hobo_permission_check
|
13
13
|
class << self
|
14
14
|
alias_method_chain :has_many, :hobo_permission_check
|
@@ -132,18 +132,18 @@ module Hobo
|
|
132
132
|
acting_user && !(self.class.has_lifecycle? && lifecycle.active_step)
|
133
133
|
end
|
134
134
|
|
135
|
-
def
|
135
|
+
def create_record_with_hobo_permission_check(*args, &b)
|
136
136
|
if permission_check_required?
|
137
137
|
create_permitted? or raise PermissionDeniedError, "#{self.class.name}#create"
|
138
138
|
end
|
139
|
-
|
139
|
+
create_record_without_hobo_permission_check(*args, &b)
|
140
140
|
end
|
141
141
|
|
142
|
-
def
|
142
|
+
def update_record_with_hobo_permission_check(*args)
|
143
143
|
if permission_check_required?
|
144
144
|
update_permitted? or raise PermissionDeniedError, "#{self.class.name}#update"
|
145
145
|
end
|
146
|
-
|
146
|
+
update_record_without_hobo_permission_check(*args)
|
147
147
|
end
|
148
148
|
|
149
149
|
def destroy_with_hobo_permission_check
|
@@ -255,6 +255,7 @@ module Hobo
|
|
255
255
|
|
256
256
|
|
257
257
|
def attribute_protected?(attribute)
|
258
|
+
return false if attribute.nil?
|
258
259
|
attribute = attribute.to_s
|
259
260
|
|
260
261
|
return true if self.class.send(:attributes_protected_by_default).include? attribute
|
data/lib/hobo/model/scopes.rb
CHANGED
@@ -2,9 +2,7 @@ module Hobo
|
|
2
2
|
module Model
|
3
3
|
module Scopes
|
4
4
|
|
5
|
-
::ActiveRecord::Associations::Builder::
|
6
|
-
::ActiveRecord::Associations::Builder::HasMany.valid_options << :scope
|
7
|
-
::ActiveRecord::Associations::Builder::HasOne.valid_options << :scope
|
5
|
+
::ActiveRecord::Associations::Builder::Association.valid_options << :scope
|
8
6
|
|
9
7
|
def self.included_in_class(klass)
|
10
8
|
klass.class_eval do
|
@@ -4,12 +4,12 @@ module Hobo
|
|
4
4
|
module ApplyScopes
|
5
5
|
|
6
6
|
def apply_scopes(scopes)
|
7
|
-
result =
|
7
|
+
result = self
|
8
8
|
scopes.each_pair do |scope, arg|
|
9
9
|
if arg.is_a?(Array)
|
10
|
-
result =
|
10
|
+
result = self.send(scope, *arg) unless arg.first.blank?
|
11
11
|
else
|
12
|
-
result =
|
12
|
+
result = self.send(scope, arg) unless arg.blank?
|
13
13
|
end
|
14
14
|
end
|
15
15
|
result
|
@@ -3,3 +3,9 @@ invoke 'hobo:admin_subsite', %w[ -q ]
|
|
3
3
|
desc "Admin Subsite files exist"
|
4
4
|
files_exist? %w( app/controllers/admin/admin_site_controller.rb app/controllers/admin/users_controller.rb app/helpers/admin/users_helper.rb app/views/taglibs/admin_site.dryml )
|
5
5
|
test_value_eql? true
|
6
|
+
|
7
|
+
desc "Admin::UsersController matches"
|
8
|
+
file_include? "app/controllers/admin/users_controller.rb",
|
9
|
+
'class Admin::UsersController < Admin::AdminSiteController',
|
10
|
+
'hobo_model_controller'
|
11
|
+
test_value_eql? true
|
metadata
CHANGED
@@ -1,84 +1,74 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hobo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
5
|
-
prerelease:
|
4
|
+
version: 2.1.0.pre1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Tom Locke
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-12-18 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: hobo_support
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - '='
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: 2.0.
|
19
|
+
version: 2.1.0.pre1
|
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
|
-
version: 2.0.
|
26
|
+
version: 2.1.0.pre1
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: hobo_fields
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - '='
|
36
32
|
- !ruby/object:Gem::Version
|
37
|
-
version: 2.0.
|
33
|
+
version: 2.1.0.pre1
|
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
|
-
version: 2.0.
|
40
|
+
version: 2.1.0.pre1
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: dryml
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - '='
|
52
46
|
- !ruby/object:Gem::Version
|
53
|
-
version: 2.0.
|
47
|
+
version: 2.1.0.pre1
|
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
|
-
version: 2.0.
|
54
|
+
version: 2.1.0.pre1
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
56
|
+
name: hobo_will_paginate
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
61
|
+
version: '0'
|
70
62
|
type: :runtime
|
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
|
-
version:
|
68
|
+
version: '0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: rubydoctest
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - '>='
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
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
|
@@ -94,7 +83,6 @@ dependencies:
|
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: shoulda
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - '>='
|
100
88
|
- !ruby/object:Gem::Version
|
@@ -102,7 +90,6 @@ dependencies:
|
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - '>='
|
108
95
|
- !ruby/object:Gem::Version
|
@@ -110,7 +97,6 @@ dependencies:
|
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: irt
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
101
|
- - '='
|
116
102
|
- !ruby/object:Gem::Version
|
@@ -118,7 +104,6 @@ dependencies:
|
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
108
|
- - '='
|
124
109
|
- !ruby/object:Gem::Version
|
@@ -126,7 +111,6 @@ dependencies:
|
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
112
|
name: mocha
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
115
|
- - '>='
|
132
116
|
- !ruby/object:Gem::Version
|
@@ -134,7 +118,6 @@ dependencies:
|
|
134
118
|
type: :development
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
122
|
- - '>='
|
140
123
|
- !ruby/object:Gem::Version
|
@@ -142,7 +125,6 @@ dependencies:
|
|
142
125
|
- !ruby/object:Gem::Dependency
|
143
126
|
name: yard
|
144
127
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
128
|
requirements:
|
147
129
|
- - '>='
|
148
130
|
- !ruby/object:Gem::Version
|
@@ -150,7 +132,6 @@ dependencies:
|
|
150
132
|
type: :development
|
151
133
|
prerelease: false
|
152
134
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
135
|
requirements:
|
155
136
|
- - '>='
|
156
137
|
- !ruby/object:Gem::Version
|
@@ -166,6 +147,7 @@ files:
|
|
166
147
|
- CHANGES-1.3.txt
|
167
148
|
- CHANGES-1.4.txt
|
168
149
|
- CHANGES-2.0.markdown
|
150
|
+
- CHANGES-2.1.markdown
|
169
151
|
- Gemfile
|
170
152
|
- LICENSE.txt
|
171
153
|
- README
|
@@ -333,8 +315,6 @@ files:
|
|
333
315
|
- test/doctest/hobo/hobo_helper.rdoctest
|
334
316
|
- test/doctest/hobo/lifecycles.rdoctest
|
335
317
|
- test/doctest/hobo/model.rdoctest
|
336
|
-
- test/doctest/hobo/multi_model_forms.rdoctest
|
337
|
-
- test/doctest/hobo/scopes.rdoctest
|
338
318
|
- test/doctest/prepare_testapp.rb
|
339
319
|
- test/irt/generators/admin_subsite.irt
|
340
320
|
- test/irt/generators/assets.irt
|
@@ -367,28 +347,26 @@ files:
|
|
367
347
|
- test/permissions/test_permissions.rb
|
368
348
|
homepage: http://hobocentral.net
|
369
349
|
licenses: []
|
350
|
+
metadata: {}
|
370
351
|
post_install_message:
|
371
352
|
rdoc_options:
|
372
353
|
- --charset=UTF-8
|
373
354
|
require_paths:
|
374
355
|
- lib
|
375
356
|
required_ruby_version: !ruby/object:Gem::Requirement
|
376
|
-
none: false
|
377
357
|
requirements:
|
378
358
|
- - '>='
|
379
359
|
- !ruby/object:Gem::Version
|
380
360
|
version: '0'
|
381
361
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
382
|
-
none: false
|
383
362
|
requirements:
|
384
363
|
- - '>='
|
385
364
|
- !ruby/object:Gem::Version
|
386
365
|
version: 1.3.6
|
387
366
|
requirements: []
|
388
367
|
rubyforge_project: hobo
|
389
|
-
rubygems_version: 1.
|
368
|
+
rubygems_version: 2.1.11
|
390
369
|
signing_key:
|
391
|
-
specification_version:
|
370
|
+
specification_version: 4
|
392
371
|
summary: The web app builder for Rails
|
393
372
|
test_files: []
|
394
|
-
has_rdoc:
|
@@ -1,260 +0,0 @@
|
|
1
|
-
Accessible Associations
|
2
|
-
{.document-title}
|
3
|
-
|
4
|
-
This chapter describes Hobo's support for nested models in forms.
|
5
|
-
This is mostly technical background -- beginners should not have to
|
6
|
-
read more than the introduction.
|
7
|
-
|
8
|
-
Contents
|
9
|
-
{.contents-heading}
|
10
|
-
|
11
|
-
- contents
|
12
|
-
{:toc}
|
13
|
-
|
14
|
-
doctest: prepare testapp environment
|
15
|
-
doctest_require: '../prepare_testapp'
|
16
|
-
|
17
|
-
>> ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(StringIO.new(''))
|
18
|
-
>>
|
19
|
-
def migrate(renames={})
|
20
|
-
up, down = Generators::Hobo::Migration::Migrator.run(renames)
|
21
|
-
ActiveRecord::Migration.class_eval(up)
|
22
|
-
ActiveRecord::Base.send(:descendants).each { |model| model.reset_column_information }
|
23
|
-
[up, down]
|
24
|
-
end
|
25
|
-
{.hidden}
|
26
|
-
|
27
|
-
# Introduction
|
28
|
-
|
29
|
-
Using multi-model forms in Hobo is very straightforward:
|
30
|
-
|
31
|
-
class Blog < ActiveRecord::Base
|
32
|
-
hobo_model
|
33
|
-
has_many :posts, :accessible => true, :inverse_of => :blog
|
34
|
-
|
35
|
-
class Post < ActiveRecord::Base
|
36
|
-
hobo_model
|
37
|
-
belongs_to :blog, :inverse_of => :posts
|
38
|
-
|
39
|
-
The `:accessible` flag is a Hobo addition, the `:inverse_of` flag is
|
40
|
-
standard Rails. `:inverse_of` is optional but highly recommended in
|
41
|
-
Rails; Hobo requires it.
|
42
|
-
|
43
|
-
Once you've done that, the default forms that Hobo builds will use the
|
44
|
-
[input-many](/api_tag_defs/input-many) tag.
|
45
|
-
|
46
|
-
`:accessible => true` works for `has_many`, `has_many :through` and
|
47
|
-
`belongs_to`, but does not work for `has_one` or
|
48
|
-
`has_and_belongs_to_many`.
|
49
|
-
|
50
|
-
It's quite common to also add the `:dependent => :destroy` flag to
|
51
|
-
accessible associations. This also used to trigger magic in Hobo, but
|
52
|
-
this additional magic has been removed and replaced with [View
|
53
|
-
Hints](/manual/viewhints). See the [Rails
|
54
|
-
rdoc](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html)
|
55
|
-
for more information on `:dependent => :destroy`.
|
56
|
-
|
57
|
-
# Model Support
|
58
|
-
|
59
|
-
We'll use rubydoctest to provide our examples for this section. Here
|
60
|
-
are the models:
|
61
|
-
|
62
|
-
>>
|
63
|
-
class Foo < ActiveRecord::Base
|
64
|
-
hobo_model
|
65
|
-
fields { name :string }
|
66
|
-
has_many :bars, :accessible => true
|
67
|
-
attr_accessible :name, :bars
|
68
|
-
end
|
69
|
-
>>
|
70
|
-
class Bar < ActiveRecord::Base
|
71
|
-
hobo_model
|
72
|
-
fields { name :string }
|
73
|
-
belongs_to :foo
|
74
|
-
attr_accessible :name, :foo, :foo_id
|
75
|
-
end
|
76
|
-
>> migrate
|
77
|
-
|
78
|
-
The `:accessible => true` option patches in
|
79
|
-
`Hobo::Model::AccessibleAssociations` to your ActiveRecord model. It
|
80
|
-
modifies the `bars=` writer function to support assigning an array of
|
81
|
-
records, an array of hashes, an array of ids, or an empty string.
|
82
|
-
|
83
|
-
## Assigning an array of records
|
84
|
-
|
85
|
-
The whole array must be assigned -- any records that are not assigned
|
86
|
-
are deleted from your association.
|
87
|
-
|
88
|
-
>> bar1 = Bar.new(:name => "bar1")
|
89
|
-
>> bar2 = Bar.new(:name => "bar2")
|
90
|
-
>> foo = Foo.new(:name => "foo1")
|
91
|
-
>> foo.bars = [bar1, bar2]
|
92
|
-
>> foo.bars.*.name
|
93
|
-
=> ["bar1", "bar2"]
|
94
|
-
>> foo.save!
|
95
|
-
|
96
|
-
>> foo.bars = [bar2]
|
97
|
-
>> foo.bars.*.name
|
98
|
-
=> ["bar2"]
|
99
|
-
>> foo.save!
|
100
|
-
|
101
|
-
>> bar2.foo.name
|
102
|
-
=> "foo1"
|
103
|
-
>> bar1.reload
|
104
|
-
>> bar1.foo
|
105
|
-
=> nil
|
106
|
-
|
107
|
-
If `:dependent => :destroy` had been set on `has_many :bars`, bar1
|
108
|
-
would now be deleted from the database. Since it hasn't, it still
|
109
|
-
exists in the database but has become orphaned.
|
110
|
-
|
111
|
-
## Assigning an array of hashes
|
112
|
-
|
113
|
-
Assigning an array of hashes maps nicely with how Rails deconstructs
|
114
|
-
your URI encoded query string. For example, your form can return
|
115
|
-
|
116
|
-
foo[bars][0][name]=bar1&foo[bars][0][name]=bar2
|
117
|
-
|
118
|
-
which Rails will decode into your params hash as
|
119
|
-
|
120
|
-
>> params = {"foo" => {"bars" => [ {"name" => "bar3"}, {"name" => "bar4"}]}}
|
121
|
-
|
122
|
-
With Hobo's accessible associations, the params hash may be directly
|
123
|
-
assigned.
|
124
|
-
|
125
|
-
>> foo.attributes = params["foo"]
|
126
|
-
>> foo.bars.*.name
|
127
|
-
=> ["bar3", "bar4"]
|
128
|
-
>> foo.save!
|
129
|
-
|
130
|
-
Because these parameters did not include an ID, Hobo created new bar
|
131
|
-
models. If you include an ID, Hobo looks up the existing record in
|
132
|
-
the database and modifies it with the parameters assigned.
|
133
|
-
|
134
|
-
>> params = {"foo" => {"bars" => [ {:name => "bar3_mod", :id => "#{foo.bars[0].id}"}]}}
|
135
|
-
|
136
|
-
>> old_bar3_id = foo.bars[0].id
|
137
|
-
>> foo.attributes = params["foo"]
|
138
|
-
>> foo.save!
|
139
|
-
>> foo.bars.*.name
|
140
|
-
=> ["bar3_mod"]
|
141
|
-
>> foo.bars[0].id == old_bar3_id
|
142
|
-
=> true
|
143
|
-
|
144
|
-
## Assigning an array of IDs
|
145
|
-
|
146
|
-
While [input-many](/api_tag_defs/input-many) returns an array of
|
147
|
-
hashes, [select-many](/api_tag_defs/select-many) returns an array of
|
148
|
-
ids. These ids must have an "@" prepended.
|
149
|
-
|
150
|
-
>> params = {"foo" => {"bars" => ["@#{bar1.id}", "@#{bar2.id}"]}}
|
151
|
-
>> foo.attributes = params["foo"]
|
152
|
-
>> foo.save!
|
153
|
-
>> foo.bars.*.name
|
154
|
-
=> ["bar1", "bar2"]
|
155
|
-
|
156
|
-
## Assigning an empty string
|
157
|
-
|
158
|
-
You can remove all elements from the association by assigning an empty
|
159
|
-
array:
|
160
|
-
|
161
|
-
>> foo.bars = []
|
162
|
-
>> foo.bars
|
163
|
-
=> []
|
164
|
-
|
165
|
-
However, there is no way to format a URI query string to make Rails
|
166
|
-
construct an empty array in its params hash, so Hobo adds a useful
|
167
|
-
shortcut to it's accessible associations:
|
168
|
-
|
169
|
-
>> foo.bars = ""
|
170
|
-
>> foo.bars
|
171
|
-
=> []
|
172
|
-
|
173
|
-
# View Support
|
174
|
-
|
175
|
-
The Rapid tags [input-many](/api_tag_defs/input-many),
|
176
|
-
[input-all](/api_tag_defs/input-all),
|
177
|
-
[select-many](/api_tag_defs/select-many) and
|
178
|
-
[check-many](/api_tag_defs/check-many) all require accessible
|
179
|
-
associations.
|
180
|
-
|
181
|
-
`input-many` may even be used in a nested fashion:
|
182
|
-
|
183
|
-
<form>
|
184
|
-
<field-list:>
|
185
|
-
<foos-view:>
|
186
|
-
<input-many>
|
187
|
-
<field-list:>
|
188
|
-
<bars-view:>
|
189
|
-
<input-many>
|
190
|
-
</input-many>
|
191
|
-
</bars-view:>
|
192
|
-
</field-list:>
|
193
|
-
</input-many>
|
194
|
-
</foos-view:>
|
195
|
-
</field-list:>
|
196
|
-
</form>
|
197
|
-
|
198
|
-
You do not need to use the accessible association tags -- standard
|
199
|
-
inputs acquire the correct `name` for use with accessible associations
|
200
|
-
when called from the appropriate context. Here's an example form that
|
201
|
-
will work with the example given above in *Model Support*
|
202
|
-
|
203
|
-
<form>
|
204
|
-
<field-list:>
|
205
|
-
<bars-view:>
|
206
|
-
<repeat>
|
207
|
-
<input:name/>
|
208
|
-
</repeat>
|
209
|
-
</bars-view:>
|
210
|
-
<field-list:>
|
211
|
-
</form>
|
212
|
-
|
213
|
-
# Controller Support
|
214
|
-
|
215
|
-
No special code is required in your controllers to support accessible
|
216
|
-
associations, even if you aren't using a Hobo controller.
|
217
|
-
|
218
|
-
# Validations
|
219
|
-
|
220
|
-
Validations simply work as you'd expect. The only thing to note is
|
221
|
-
that validation errors in a child object will cause the parent
|
222
|
-
object to receive an error message of "..." on the association.
|
223
|
-
|
224
|
-
# Transactions
|
225
|
-
|
226
|
-
Hobo's accessible associations do not do any explicit saves so any new
|
227
|
-
child objects are not saved until the parent object is saved. Rails
|
228
|
-
wraps this save in a transaction, so any save is an all or nothing
|
229
|
-
deal even though parents and children are saved via different SQL
|
230
|
-
statements.
|
231
|
-
|
232
|
-
# Rails 2.3 nested models
|
233
|
-
|
234
|
-
Rails 2.3 includes a functionality similar to Hobo's accessible
|
235
|
-
associations. The Hobo version is based on an early version of the
|
236
|
-
Rails functionality, but unfortunately the Rails version changed
|
237
|
-
significantly between the time that the Hobo version was released and
|
238
|
-
when Rails 2.3 was released.
|
239
|
-
|
240
|
-
For more information on Rails 2.3's `accept_nested_attributes_for`,
|
241
|
-
see [the Ruby on Rails
|
242
|
-
blog](http://weblog.rubyonrails.org/2009/1/26/nested-model-forms) or
|
243
|
-
[Ryan Daigle's blog](http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes).
|
244
|
-
|
245
|
-
The two versions use a different model: in Hobo the whole array is
|
246
|
-
assigned, allowing add, delete or update via a single mechanism. In
|
247
|
-
rails, there's a different mechanism for adding or deleting objects
|
248
|
-
from the association, and there's no method for update.
|
249
|
-
|
250
|
-
Each version have their pluses and minuses. The Hobo version is
|
251
|
-
conceptually simpler, but it starts to get unwieldy if there are a
|
252
|
-
large number of elements in the association.
|
253
|
-
|
254
|
-
Both mechanisms are compatible and may be enabled simultaneously.
|
255
|
-
|
256
|
-
It's certainly possible that later versions of Rapid will acquire tags
|
257
|
-
that will require `accept_nested_attributes_for`. However, it's
|
258
|
-
unlikely that Hobo will drop support for accessible associations
|
259
|
-
unless ActiveRecord itself changes significantly.
|
260
|
-
|