hobo 0.6.1 → 0.6.2
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.
- data/bin/hobo +3 -2
- data/hobo_files/plugin/CHANGES.txt +299 -2
- data/hobo_files/plugin/Rakefile +12 -10
- data/hobo_files/plugin/generators/hobo/templates/guest.rb +1 -13
- data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +11 -7
- data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +1 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +1 -1
- data/hobo_files/plugin/generators/hobo_rapid/templates/lowpro.js +405 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +1 -1
- data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +1 -9
- data/hobo_files/plugin/init.rb +5 -0
- data/hobo_files/plugin/lib/active_record/has_many_association.rb +1 -1
- data/hobo_files/plugin/lib/extensions.rb +26 -5
- data/hobo_files/plugin/lib/extensions/test_case.rb +1 -1
- data/hobo_files/plugin/lib/hobo.rb +37 -11
- data/hobo_files/plugin/lib/hobo/authenticated_user.rb +7 -2
- data/hobo_files/plugin/lib/hobo/authentication_support.rb +7 -6
- data/hobo_files/plugin/lib/hobo/composite_model.rb +5 -0
- data/hobo_files/plugin/lib/hobo/controller.rb +4 -4
- data/hobo_files/plugin/lib/hobo/dryml.rb +5 -5
- data/hobo_files/plugin/lib/hobo/dryml/part_context.rb +3 -6
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +16 -15
- data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +24 -20
- data/hobo_files/plugin/lib/hobo/email_address.rb +4 -0
- data/hobo_files/plugin/lib/hobo/field_spec.rb +2 -1
- data/hobo_files/plugin/lib/hobo/guest.rb +21 -0
- data/hobo_files/plugin/lib/hobo/hobo_helper.rb +42 -2
- data/hobo_files/plugin/lib/hobo/http_parameters.rb +225 -0
- data/hobo_files/plugin/lib/hobo/model.rb +55 -37
- data/hobo_files/plugin/lib/hobo/model_controller.rb +151 -151
- data/hobo_files/plugin/lib/hobo/model_queries.rb +30 -5
- data/hobo_files/plugin/lib/hobo/user_controller.rb +27 -16
- data/hobo_files/plugin/lib/hobo/where_fragment.rb +6 -1
- data/hobo_files/plugin/tags/rapid.dryml +88 -58
- data/hobo_files/plugin/tags/rapid_document_tags.dryml +5 -5
- data/hobo_files/plugin/tags/rapid_editing.dryml +3 -3
- data/hobo_files/plugin/tags/rapid_forms.dryml +35 -26
- data/hobo_files/plugin/tags/rapid_navigation.dryml +13 -12
- data/hobo_files/plugin/tags/rapid_pages.dryml +35 -31
- data/hobo_files/plugin/tags/rapid_plus.dryml +41 -0
- data/hobo_files/plugin/tags/rapid_support.dryml +18 -9
- data/hobo_files/plugin/tasks/dump_fixtures.rake +61 -0
- metadata +7 -11
- data/hobo_files/plugin/spec/fixtures/users.yml +0 -9
- data/hobo_files/plugin/spec/spec.opts +0 -6
- data/hobo_files/plugin/spec/spec_helper.rb +0 -28
- data/hobo_files/plugin/spec/unit/hobo/dryml/template_spec.rb +0 -650
@@ -194,11 +194,13 @@ module Hobo::Dryml
|
|
194
194
|
def new_object_context(new_this)
|
195
195
|
new_context do
|
196
196
|
@_this_parent,@_this_field,@_this_type = if new_this.respond_to?(:proxy_reflection)
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
197
|
+
refl = new_this.proxy_reflection
|
198
|
+
[new_this.proxy_owner, refl.name, refl]
|
199
|
+
else
|
200
|
+
# In dryml, TrueClass is the 'boolean' class
|
201
|
+
t = new_this.class == FalseClass ? TrueClass : new_this.class
|
202
|
+
[nil, nil, t]
|
203
|
+
end
|
202
204
|
@_this = new_this
|
203
205
|
yield
|
204
206
|
end
|
@@ -207,27 +209,25 @@ module Hobo::Dryml
|
|
207
209
|
|
208
210
|
def new_field_context(field_path, tag_this=nil)
|
209
211
|
new_context do
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
obj = tag_this || this
|
219
|
-
for field in path
|
220
|
-
parent = obj
|
221
|
-
obj = Hobo.get_field(parent, field)
|
222
|
-
end
|
212
|
+
path = if field_path.is_a? Array
|
213
|
+
field_path
|
214
|
+
elsif field_path.is_a? String
|
215
|
+
field_path.split('.')
|
216
|
+
else
|
217
|
+
[field_path]
|
218
|
+
end
|
219
|
+
parent, field, obj = Hobo.get_field_path(tag_this || this, path)
|
223
220
|
|
224
221
|
type = if (obj.nil? or obj.respond_to?(:proxy_reflection)) and
|
225
222
|
parent.class.respond_to?(:field_type) and field_type = parent.class.field_type(field)
|
226
223
|
field_type
|
224
|
+
elsif obj == false
|
225
|
+
# In dryml, TrueClass is the 'boolean' class
|
226
|
+
TrueClass
|
227
227
|
else
|
228
228
|
obj.class
|
229
229
|
end
|
230
|
-
|
230
|
+
|
231
231
|
@_this, @_this_parent, @_this_field, @_this_type = obj, parent, field, type
|
232
232
|
@_form_field_path += path if @_form_field_path
|
233
233
|
yield
|
@@ -409,7 +409,11 @@ module Hobo::Dryml
|
|
409
409
|
|
410
410
|
|
411
411
|
def render_tag(tag_name, attributes)
|
412
|
-
(
|
412
|
+
if respond_to?(tag_name)
|
413
|
+
(send(tag_name, attributes) + part_contexts_storage_tag).strip
|
414
|
+
else
|
415
|
+
false
|
416
|
+
end
|
413
417
|
end
|
414
418
|
|
415
419
|
|
@@ -23,7 +23,8 @@ module Hobo
|
|
23
23
|
elsif options[:length]
|
24
24
|
:string
|
25
25
|
else
|
26
|
-
Hobo.field_types[type]
|
26
|
+
field_type = Hobo.field_types[type]
|
27
|
+
field_type && field_type::COLUMN_TYPE or raise UnknownSqlTypeError, [model, name, type]
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
@@ -15,13 +15,13 @@ module Hobo
|
|
15
15
|
@current_user = if session and id = session[:user]
|
16
16
|
Hobo.object_from_dom_id(id)
|
17
17
|
else
|
18
|
-
Guest.new
|
18
|
+
::Guest.new
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
|
23
23
|
def logged_in?
|
24
|
-
!
|
24
|
+
!current_user.guest?
|
25
25
|
end
|
26
26
|
|
27
27
|
|
@@ -307,6 +307,46 @@ module Hobo
|
|
307
307
|
end
|
308
308
|
|
309
309
|
|
310
|
+
# Login url for a given user record or user class
|
311
|
+
def login_url(user_or_class)
|
312
|
+
c = user_or_class.is_a?(Class) ? user_or_class : user_or_class.class
|
313
|
+
send("#{c.name.underscore}_login_url") rescue nil
|
314
|
+
end
|
315
|
+
|
316
|
+
|
317
|
+
# Login url for a given user record or user class
|
318
|
+
def logout_url(user_or_class=nil)
|
319
|
+
c = if user_or_class.nil?
|
320
|
+
current_user.class
|
321
|
+
elsif user_or_class.is_a?(Class)
|
322
|
+
user_or_class
|
323
|
+
else
|
324
|
+
user_or_class.class
|
325
|
+
end
|
326
|
+
send("#{c.name.underscore}_logout_url") rescue nil
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
# Sign-up url for a given user record or user class
|
331
|
+
def signup_url(user_or_class)
|
332
|
+
c = user_or_class.is_a?(Class) ? user_or_class : user_or_class.class
|
333
|
+
send("#{c.name.underscore}_signup_url") rescue nil
|
334
|
+
end
|
335
|
+
|
336
|
+
def query_params
|
337
|
+
query = request.request_uri.match(/(?:\?(.+))/)._?[1]
|
338
|
+
if query
|
339
|
+
params = query.split('&')
|
340
|
+
pairs = params.map do |param|
|
341
|
+
pair = param.split('=')
|
342
|
+
pair.length == 1 ? pair + [''] : pair
|
343
|
+
end
|
344
|
+
Hash[*pairs.flatten]
|
345
|
+
else
|
346
|
+
{}
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
310
350
|
# debugging support
|
311
351
|
|
312
352
|
def abort_with(*args)
|
@@ -0,0 +1,225 @@
|
|
1
|
+
module Hobo
|
2
|
+
|
3
|
+
module HttpParameters
|
4
|
+
|
5
|
+
class PermissionDeniedError < RuntimeError; end
|
6
|
+
class InvalidError < RuntimeError; end
|
7
|
+
|
8
|
+
def initialize_record(record, params)
|
9
|
+
update_without_tracking(record, params)
|
10
|
+
record.set_creator(current_user)
|
11
|
+
(@to_create ||= []) << record
|
12
|
+
record
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def update_record(record, params)
|
17
|
+
return if params.blank?
|
18
|
+
|
19
|
+
original = record.duplicate
|
20
|
+
# 'duplicate' can set these, but they can
|
21
|
+
# conflict with the changes so we clear them
|
22
|
+
@this.send(:clear_aggregation_cache)
|
23
|
+
@this.send(:clear_association_cache)
|
24
|
+
|
25
|
+
(@to_update ||= []) << [original, record]
|
26
|
+
|
27
|
+
update_without_tracking(record, params)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def update_without_tracking(record, params)
|
32
|
+
params && params.each_pair do |field_name, value|
|
33
|
+
field = if (create = field_name =~ /^\+/)
|
34
|
+
field_name[1..-1].to_sym
|
35
|
+
else
|
36
|
+
field_name.to_sym
|
37
|
+
end
|
38
|
+
refl = record.class.reflections[field]
|
39
|
+
|
40
|
+
if refl._?.macro == :belongs_to
|
41
|
+
if create
|
42
|
+
new_for_belongs_to(record, refl, value)
|
43
|
+
else
|
44
|
+
update_belongs_to(record, refl, value)
|
45
|
+
end
|
46
|
+
|
47
|
+
elsif Hobo.simple_has_many_association?(refl)
|
48
|
+
raise HoboError, "invalid HTTP parameter #{field_name}" if create
|
49
|
+
update_has_many(record, refl, value)
|
50
|
+
|
51
|
+
else
|
52
|
+
raise HoboError, "invalid HTTP parameter #{field_name}" if create
|
53
|
+
update_primitive(record, field, value)
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def new_for_belongs_to(record, refl, fields)
|
61
|
+
# person[+home][address]=blah Create new home and set address (PUT POST)
|
62
|
+
|
63
|
+
target = refl.klass.new
|
64
|
+
initialize_record(target, fields)
|
65
|
+
record.send("#{refl.name}=", target)
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def update_belongs_to(record, refl, value)
|
70
|
+
if value.is_a? String
|
71
|
+
# Update belongs_to to reference some existing record
|
72
|
+
|
73
|
+
target = if value.starts_with?('@')
|
74
|
+
# person[home]=@home_12 Reference different existing home (PUT POST)
|
75
|
+
|
76
|
+
Hobo.object_from_dom_id(value[1..-1])
|
77
|
+
elsif refl.klass.id_name?
|
78
|
+
# product[category]=garden Reference existing category with id or name (PUT POST)
|
79
|
+
|
80
|
+
refl.klass.find_by_id_name(value)
|
81
|
+
else
|
82
|
+
raise HoboError, "invalid HTTP parameter" if create
|
83
|
+
end
|
84
|
+
record.send("#{refl.name}=", target)
|
85
|
+
|
86
|
+
else
|
87
|
+
# Update state of current belongs_to target
|
88
|
+
# person[home][address]=blah Update existing home.address (PUT)
|
89
|
+
raise HoboError, "invalid HTTP parameter" unless params[:action] == "update"
|
90
|
+
|
91
|
+
target = record.send(refl.name)
|
92
|
+
raise HoboError, "invalid HTTP parameter" if target.nil?
|
93
|
+
update_record(target, value)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def update_has_many(record, refl, items)
|
99
|
+
new_items, changed_items = items.partition_hash {|k,v| k =~ /^\+/}
|
100
|
+
|
101
|
+
new_items.keys.sort_by{|k|k.to_i}.each do |k|
|
102
|
+
# home[people][+1][name]=blah Create new Person with fkey refing to this home and set name (PUT POST)
|
103
|
+
fields = new_items[k]
|
104
|
+
new_for_has_many(record, refl, fields)
|
105
|
+
end
|
106
|
+
|
107
|
+
changed_items.each_pair do |id, value|
|
108
|
+
# Change to existing record - only valid on PUTs
|
109
|
+
raise HoboError, "invalid HTTP parameter" unless params[:action] == "update"
|
110
|
+
|
111
|
+
target = id =~ /_/ ? Hobo.object_from_dom_id(id) : refl.klass.find(id)
|
112
|
+
# Ensure the target is actually in this has_many
|
113
|
+
raise HoboError, "invalid http parameter" unless target.send(refl.primary_key_name) == record.id
|
114
|
+
|
115
|
+
if value.is_a?(String) && value.downcase == "delete"
|
116
|
+
# home[people][45]=delete Delete Person[45] (PUT)
|
117
|
+
delete_record(target)
|
118
|
+
|
119
|
+
else
|
120
|
+
# home[people][45][name]=blah Update Person[45].name (PUT)
|
121
|
+
raise HoboError, "invalid http parameter" unless value.is_a?(Hash) # field/value pairs
|
122
|
+
update_record(target, value)
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
def new_for_has_many(record, refl, value)
|
130
|
+
# home[people][+1][name]=blah Create new Person with fkey refing to this home and set name (PUT POST)
|
131
|
+
|
132
|
+
new_record = record.send(refl.name).new
|
133
|
+
initialize_record(new_record, value)
|
134
|
+
record.send("#{refl.name}").target << new_record
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def delete_record(record)
|
139
|
+
raise HoboError, "invalid HTTP parameter" unless params[:action] == "update"
|
140
|
+
(@to_delete ||= []) << record
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
def update_primitive(record, field, value)
|
145
|
+
# person[name]=fred (POST PUT)
|
146
|
+
field_type = record.class.field_type(field)
|
147
|
+
record.send("#{field}=", param_to_value(field_type, value))
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
def parse_datetime(s)
|
152
|
+
defined?(Chronic) ? Chronic.parse(s) : Time.parse(s)
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
def param_to_value(field_type, value)
|
157
|
+
if field_type.nil?
|
158
|
+
value
|
159
|
+
elsif field_type <= Date
|
160
|
+
if value.is_a? Hash
|
161
|
+
Date.new(*(%w{year month day}.map{|s| value[s].to_i}))
|
162
|
+
elsif value.is_a? String
|
163
|
+
dt = parse_datetime(value)
|
164
|
+
dt && dt.to_date
|
165
|
+
end
|
166
|
+
elsif field_type <= Time
|
167
|
+
if value.is_a? Hash
|
168
|
+
Time.local(*(%w{year month day hour minute}.map{|s| value[s].to_i}))
|
169
|
+
elsif value.is_a? String
|
170
|
+
parse_datetime(value)
|
171
|
+
end
|
172
|
+
elsif field_type <= TrueClass
|
173
|
+
(value.is_a?(String) && value.strip.downcase.in?(['0', 'false']) || value.blank?) ? false : true
|
174
|
+
else
|
175
|
+
# primitive field
|
176
|
+
value
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
def check_permissions_and_apply_changes
|
182
|
+
valid = true
|
183
|
+
for old, new in @to_update
|
184
|
+
raise PermissionDeniedError unless Hobo.can_update?(current_user, old, new)
|
185
|
+
new_valid = new.save
|
186
|
+
valid &&= new_valid
|
187
|
+
end if @to_update
|
188
|
+
|
189
|
+
for record in @to_create
|
190
|
+
raise PermissionDeniedError unless Hobo.can_create?(current_user, record)
|
191
|
+
# check if it's new because it might have already been saved as a result of the updates
|
192
|
+
record_valid = record.save if record.new_record?
|
193
|
+
valid &&= record_valid
|
194
|
+
end if @to_create
|
195
|
+
|
196
|
+
for record in @to_delete
|
197
|
+
raise PermissionDeniedError unless Hobo.can_delete?(current_user, record)
|
198
|
+
record.destroy
|
199
|
+
end if @to_delete
|
200
|
+
|
201
|
+
valid
|
202
|
+
ensure
|
203
|
+
@to_update = @to_create = @to_delete = nil
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
def secure_change_transaction
|
208
|
+
valid = nil
|
209
|
+
begin
|
210
|
+
ActiveRecord::Base.transaction do
|
211
|
+
yield
|
212
|
+
valid = check_permissions_and_apply_changes
|
213
|
+
raise InvalidError unless valid
|
214
|
+
end
|
215
|
+
rescue PermissionDeniedError
|
216
|
+
return :not_allowed
|
217
|
+
rescue InvalidError
|
218
|
+
return :invalid
|
219
|
+
end
|
220
|
+
:valid
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
@@ -28,6 +28,8 @@ module Hobo
|
|
28
28
|
alias_method_chain :has_many, :defined_scopes
|
29
29
|
alias_method_chain :belongs_to, :foreign_key_declaration
|
30
30
|
end
|
31
|
+
# respond_to? is slow on AR objects, use this instead where possible
|
32
|
+
base.send(:alias_method, :has_hobo_method?, :respond_to_without_attributes?)
|
31
33
|
end
|
32
34
|
|
33
35
|
module ClassMethods
|
@@ -64,10 +66,13 @@ module Hobo
|
|
64
66
|
|
65
67
|
def field(name, *args)
|
66
68
|
type = args.shift
|
67
|
-
options =
|
69
|
+
options = args.extract_options!
|
68
70
|
@model.send(:set_field_type, name => type) unless
|
69
71
|
type.in?(@model.connection.native_database_types.keys - [:text])
|
70
72
|
@model.field_specs[name] = FieldSpec.new(@model, name, type, options)
|
73
|
+
|
74
|
+
@model.send(:validates_presence_of, name) if :required.in?(args)
|
75
|
+
@model.send(:validates_uniqueness_of, name) if :unique.in?(args)
|
71
76
|
end
|
72
77
|
|
73
78
|
def method_missing(name, *args)
|
@@ -102,6 +107,13 @@ module Hobo
|
|
102
107
|
types.each_pair do |field, type|
|
103
108
|
type_class = Hobo.field_types[type] || type
|
104
109
|
field_types[field] = type_class
|
110
|
+
|
111
|
+
if "validate".in?(type_class.instance_methods)
|
112
|
+
self.validate do |record|
|
113
|
+
v = record.send(field).validate
|
114
|
+
record.errors.add(field, v) if v.is_a?(String)
|
115
|
+
end
|
116
|
+
end
|
105
117
|
end
|
106
118
|
end
|
107
119
|
|
@@ -129,15 +141,10 @@ module Hobo
|
|
129
141
|
public :never_show?
|
130
142
|
|
131
143
|
def set_creator_attr(attr)
|
132
|
-
|
133
|
-
def creator
|
134
|
-
#{attr};
|
135
|
-
end
|
136
|
-
def creator=(x)
|
137
|
-
self.#{attr} = x;
|
138
|
-
end
|
139
|
-
}
|
144
|
+
@creator_attr = attr.to_sym
|
140
145
|
end
|
146
|
+
attr_reader :creator_attr
|
147
|
+
public :creator_attr
|
141
148
|
|
142
149
|
def set_search_columns(*columns)
|
143
150
|
class_eval %{
|
@@ -225,27 +232,34 @@ module Hobo
|
|
225
232
|
end
|
226
233
|
|
227
234
|
|
228
|
-
def conditions(&b)
|
229
|
-
|
235
|
+
def conditions(*args, &b)
|
236
|
+
if args.empty?
|
237
|
+
ModelQueries.new(self).instance_eval(&b).to_sql
|
238
|
+
else
|
239
|
+
ModelQueries.new(self).instance_exec(*args, &b).to_sql
|
240
|
+
end
|
230
241
|
end
|
231
|
-
|
242
|
+
|
232
243
|
|
233
244
|
def find(*args, &b)
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
245
|
+
options = args.extract_options!
|
246
|
+
if args.first.in?([:all, :first]) && options[:order] == :default
|
247
|
+
options = if default_order.blank?
|
248
|
+
options - [:order]
|
249
|
+
else
|
250
|
+
options.merge(:order => "#{table_name}.#{default_order}")
|
251
|
+
end
|
252
|
+
end
|
241
253
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
254
|
+
if b && !(block_conditions = conditions(&b)).blank?
|
255
|
+
c = if !options[:conditions].blank?
|
256
|
+
"(#{options[:conditons]}) and (#{block_conditions})"
|
257
|
+
else
|
258
|
+
block_conditions
|
259
|
+
end
|
260
|
+
super(args.first, options.merge(:conditions => c))
|
247
261
|
else
|
248
|
-
super(*args)
|
262
|
+
super(*args + [options])
|
249
263
|
end
|
250
264
|
end
|
251
265
|
|
@@ -271,8 +285,8 @@ module Hobo
|
|
271
285
|
end
|
272
286
|
end
|
273
287
|
|
274
|
-
def
|
275
|
-
|
288
|
+
def creator_type
|
289
|
+
reflections[@creator_attr]._?.klass
|
276
290
|
end
|
277
291
|
|
278
292
|
def search_columns
|
@@ -366,12 +380,13 @@ module Hobo
|
|
366
380
|
if find_scope
|
367
381
|
# Calling instance_variable_get directly causes self to
|
368
382
|
# get loaded, hence this trick
|
369
|
-
assoc = Kernel.instance_method(:instance_variable_get).bind(self).call("@#{name}")
|
383
|
+
assoc = Kernel.instance_method(:instance_variable_get).bind(self).call("@#{name}_scope")
|
370
384
|
|
371
385
|
unless assoc
|
372
386
|
options = proxy_reflection.options
|
373
387
|
has_many_conditions = options.has_key?(:conditions)
|
374
|
-
|
388
|
+
source = proxy_reflection.source_reflection
|
389
|
+
scope_conditions = find_scope[:conditions]
|
375
390
|
conditions = if has_many_conditions && scope_conditions
|
376
391
|
"(#{scope_conditions}) AND (#{has_many_conditions})"
|
377
392
|
else
|
@@ -379,23 +394,26 @@ module Hobo
|
|
379
394
|
end
|
380
395
|
|
381
396
|
options = options.merge(find_scope).update(:conditions => conditions,
|
382
|
-
|
383
|
-
|
397
|
+
:class_name => proxy_reflection.klass.name,
|
398
|
+
:foreign_key => proxy_reflection.primary_key_name)
|
399
|
+
options[:source] = source.name if source
|
400
|
+
|
384
401
|
r = ActiveRecord::Reflection::AssociationReflection.new(:has_many,
|
385
402
|
name,
|
386
403
|
options,
|
387
|
-
|
404
|
+
proxy_owner.class)
|
405
|
+
|
388
406
|
@reflections ||= {}
|
389
407
|
@reflections[name] = r
|
390
408
|
|
391
|
-
assoc = if
|
409
|
+
assoc = if source
|
392
410
|
ActiveRecord::Associations::HasManyThroughAssociation
|
393
411
|
else
|
394
412
|
ActiveRecord::Associations::HasManyAssociation
|
395
413
|
end.new(self.proxy_owner, r)
|
396
|
-
|
414
|
+
|
397
415
|
# Calling directly causes self to get loaded
|
398
|
-
Kernel.instance_method(:instance_variable_set).bind(self).call("@#{name}", assoc)
|
416
|
+
Kernel.instance_method(:instance_variable_set).bind(self).call("@#{name}_scope", assoc)
|
399
417
|
end
|
400
418
|
assoc
|
401
419
|
else
|
@@ -407,7 +425,7 @@ module Hobo
|
|
407
425
|
|
408
426
|
|
409
427
|
def has_many_with_defined_scopes(name, *args, &block)
|
410
|
-
options =
|
428
|
+
options = args.extract_options!
|
411
429
|
if options.has_key?(:extend) || block
|
412
430
|
# Normal has_many
|
413
431
|
has_many_without_defined_scopes(name, *args + [options], &block)
|
@@ -420,7 +438,7 @@ module Hobo
|
|
420
438
|
|
421
439
|
|
422
440
|
def set_creator(user)
|
423
|
-
self.
|
441
|
+
self.send("#{self.class.creator_attr}=", user) if (t = self.class.creator_type) && user.is_a?(t)
|
424
442
|
end
|
425
443
|
|
426
444
|
|