hobo 0.8.5 → 0.8.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +41 -0
- data/Manifest +1 -5
- data/Rakefile +10 -3
- data/bin/hobo +38 -15
- data/dryml_generators/rapid/cards.dryml.erb +7 -7
- data/dryml_generators/rapid/pages.dryml.erb +52 -24
- data/hobo.gemspec +42 -322
- data/init.rb +0 -7
- data/lib/active_record/association_collection.rb +9 -0
- data/lib/hobo.rb +13 -14
- data/lib/hobo/accessible_associations.rb +32 -7
- data/lib/hobo/authentication_support.rb +1 -1
- data/lib/hobo/controller.rb +5 -7
- data/lib/hobo/dryml.rb +9 -2
- data/lib/hobo/dryml/dryml_builder.rb +11 -12
- data/lib/hobo/dryml/dryml_doc.rb +22 -24
- data/lib/hobo/dryml/dryml_generator.rb +41 -4
- data/lib/hobo/dryml/part_context.rb +5 -3
- data/lib/hobo/dryml/template.rb +7 -7
- data/lib/hobo/dryml/template_environment.rb +11 -22
- data/lib/hobo/dryml/template_handler.rb +94 -25
- data/lib/hobo/find_for.rb +2 -2
- data/lib/hobo/hobo_helper.rb +21 -21
- data/lib/hobo/include_in_save.rb +9 -5
- data/lib/hobo/lifecycles/transition.rb +2 -2
- data/lib/hobo/model.rb +11 -61
- data/lib/hobo/model_controller.rb +28 -29
- data/lib/hobo/model_router.rb +12 -13
- data/lib/hobo/permissions.rb +47 -37
- data/lib/hobo/permissions/associations.rb +1 -1
- data/lib/hobo/scopes/association_proxy_extensions.rb +5 -6
- data/lib/hobo/scopes/automatic_scopes.rb +7 -4
- data/lib/hobo/tasks/rails.rb +4 -0
- data/lib/hobo/user.rb +0 -1
- data/lib/hobo/user_controller.rb +3 -1
- data/lib/hobo/view_hints.rb +17 -3
- data/rails_generators/hobo/hobo_generator.rb +1 -0
- data/rails_generators/hobo_front_controller/templates/functional_test.rb +1 -11
- data/rails_generators/hobo_front_controller/templates/index.dryml +1 -6
- data/rails_generators/hobo_rapid/hobo_rapid_generator.rb +1 -0
- data/rails_generators/hobo_rapid/templates/hobo-rapid.css +3 -2
- data/rails_generators/hobo_rapid/templates/hobo-rapid.js +24 -15
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +17 -12
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +6 -2
- data/rails_generators/hobo_rapid/templates/themes/clean/views/clean.dryml +2 -2
- data/rails_generators/hobo_user_model/templates/forgot_password.erb +2 -2
- data/rails_generators/hobo_user_model/templates/model.rb +2 -2
- data/taglibs/rapid.dryml +3 -2
- data/taglibs/rapid_core.dryml +21 -16
- data/taglibs/rapid_document_tags.dryml +1 -1
- data/taglibs/rapid_editing.dryml +7 -10
- data/taglibs/rapid_forms.dryml +115 -26
- data/taglibs/rapid_generics.dryml +13 -3
- data/taglibs/rapid_lifecycles.dryml +18 -1
- data/taglibs/rapid_navigation.dryml +50 -61
- data/taglibs/rapid_pages.dryml +103 -19
- data/taglibs/rapid_plus.dryml +54 -6
- data/taglibs/rapid_support.dryml +38 -1
- data/taglibs/rapid_user_pages.dryml +17 -5
- data/test/permissions/models/models.rb +24 -12
- data/test/permissions/models/test.sqlite3 +0 -0
- metadata +6 -15
- data/lib/extensions/test_case.rb +0 -129
- data/lib/hobo/composite_model.rb +0 -73
- data/lib/hobo/model_support.rb +0 -44
- data/tasks/fix_dryml.rake +0 -143
- data/tasks/generate_tag_reference.rake +0 -192
- data/test/dryml/complilation_test.rb +0 -261
data/lib/hobo/model.rb
CHANGED
@@ -6,7 +6,7 @@ module Hobo
|
|
6
6
|
|
7
7
|
NAME_FIELD_GUESS = %w(name title)
|
8
8
|
PRIMARY_CONTENT_GUESS = %w(description body content profile)
|
9
|
-
SEARCH_COLUMNS_GUESS = %w(name title body content profile)
|
9
|
+
SEARCH_COLUMNS_GUESS = %w(name title body description content profile)
|
10
10
|
|
11
11
|
|
12
12
|
def self.included(base)
|
@@ -86,7 +86,9 @@ module Hobo
|
|
86
86
|
end
|
87
87
|
|
88
88
|
# ...but only return the ones that registered themselves
|
89
|
-
@model_names
|
89
|
+
@model_names.map do |name|
|
90
|
+
name.safe_constantize || (@model_names.delete name; nil)
|
91
|
+
end.compact
|
90
92
|
end
|
91
93
|
|
92
94
|
|
@@ -133,9 +135,6 @@ module Hobo
|
|
133
135
|
|
134
136
|
module ClassMethods
|
135
137
|
|
136
|
-
# include methods also shared by CompositeModel
|
137
|
-
#include ModelSupport::ClassMethods
|
138
|
-
|
139
138
|
attr_accessor :creator_attribute
|
140
139
|
attr_writer :name_attribute, :primary_content_attribute
|
141
140
|
|
@@ -204,7 +203,7 @@ module Hobo
|
|
204
203
|
if options[:polymorphic]
|
205
204
|
class_eval %{
|
206
205
|
def #{name}_is?(target)
|
207
|
-
target.
|
206
|
+
target.class.name == self.#{refl.options[:foreign_type]} && target.id == self.#{refl.primary_key_name}
|
208
207
|
end
|
209
208
|
def #{name}_changed?
|
210
209
|
#{refl.primary_key_name}_changed? || #{refl.options[:foreign_type]}_changed?
|
@@ -213,7 +212,7 @@ module Hobo
|
|
213
212
|
else
|
214
213
|
class_eval %{
|
215
214
|
def #{name}_is?(target)
|
216
|
-
target.id == self.#{refl.primary_key_name}
|
215
|
+
target.class == ::#{refl.klass.name} && target.id == self.#{refl.primary_key_name}
|
217
216
|
end
|
218
217
|
def #{name}_changed?
|
219
218
|
#{refl.primary_key_name}_changed?
|
@@ -359,10 +358,7 @@ module Hobo
|
|
359
358
|
|
360
359
|
def method_missing(name, *args, &block)
|
361
360
|
name = name.to_s
|
362
|
-
if name
|
363
|
-
# FIXME: Do we need this now?
|
364
|
-
call_method_chain(name, args, &block)
|
365
|
-
elsif create_automatic_scope(name)
|
361
|
+
if create_automatic_scope(name)
|
366
362
|
send(name.to_sym, *args, &block)
|
367
363
|
else
|
368
364
|
super(name.to_sym, *args, &block)
|
@@ -375,13 +371,6 @@ module Hobo
|
|
375
371
|
end
|
376
372
|
|
377
373
|
|
378
|
-
def call_method_chain(chain, args, &block)
|
379
|
-
parts = chain.split(".")
|
380
|
-
s = parts[0..-2].inject(self) { |m, scope| m.send(scope) }
|
381
|
-
s.send(parts.last, *args)
|
382
|
-
end
|
383
|
-
|
384
|
-
|
385
374
|
def to_url_path
|
386
375
|
"#{name.underscore.pluralize}"
|
387
376
|
end
|
@@ -412,7 +401,7 @@ module Hobo
|
|
412
401
|
def to_param
|
413
402
|
name_attr = self.class.name_attribute and name = send(name_attr)
|
414
403
|
if name_attr && !name.blank? && id.is_a?(Fixnum)
|
415
|
-
readable = name.to_s.downcase.gsub(/[^a-z0-9]+/, '-').
|
404
|
+
readable = name.to_s.downcase.gsub(/[^a-z0-9]+/, '-').remove(/-+$/).remove(/^-+/).split('-')[0..5].join('-')
|
416
405
|
@to_param ||= "#{id}-#{readable}"
|
417
406
|
else
|
418
407
|
id.to_s
|
@@ -431,6 +420,9 @@ module Hobo
|
|
431
420
|
end
|
432
421
|
|
433
422
|
|
423
|
+
# We deliberately give these three methods unconventional (java-esque) names to avoid
|
424
|
+
# polluting the application namespace
|
425
|
+
|
434
426
|
def set_creator(user)
|
435
427
|
set_creator!(user) unless get_creator
|
436
428
|
end
|
@@ -452,53 +444,11 @@ module Hobo
|
|
452
444
|
end
|
453
445
|
|
454
446
|
|
455
|
-
# We deliberately give this method an unconventional name to avoid
|
456
|
-
# polluting the application namespace too badly
|
457
447
|
def get_creator
|
458
448
|
self.class.creator_attribute && send(self.class.creator_attribute)
|
459
449
|
end
|
460
450
|
|
461
451
|
|
462
|
-
def duplicate
|
463
|
-
copy = self.class.new
|
464
|
-
copy.copy_instance_variables_from(self, ["@attributes_cache"])
|
465
|
-
copy.instance_variable_set("@attributes", @attributes.dup)
|
466
|
-
copy.instance_variable_set("@new_record", nil) unless new_record?
|
467
|
-
|
468
|
-
# Shallow copy of belongs_to associations
|
469
|
-
for refl in self.class.reflections.values
|
470
|
-
if refl.macro == :belongs_to and (target = self.send(refl.name))
|
471
|
-
bta = ActiveRecord::Associations::BelongsToAssociation.new(copy, refl)
|
472
|
-
bta.replace(target)
|
473
|
-
copy.instance_variable_set("@#{refl.name}", bta)
|
474
|
-
end
|
475
|
-
end
|
476
|
-
copy
|
477
|
-
end
|
478
|
-
|
479
|
-
|
480
|
-
def same_fields?(other, *fields)
|
481
|
-
return true if other.nil?
|
482
|
-
|
483
|
-
fields = fields.flatten
|
484
|
-
fields.all?{|f| self.send(f) == other.send(f)}
|
485
|
-
end
|
486
|
-
|
487
|
-
|
488
|
-
def only_changed_fields?(other, *changed_fields)
|
489
|
-
return true if other.nil?
|
490
|
-
|
491
|
-
changed_fields = changed_fields.flatten.*.to_s
|
492
|
-
all_cols = self.class.columns.*.name - []
|
493
|
-
all_cols.all?{|c| c.in?(changed_fields) || self.send(c) == other.send(c) }
|
494
|
-
end
|
495
|
-
|
496
|
-
|
497
|
-
def compose_with(object, use=nil)
|
498
|
-
CompositeModel.new_for([self, object])
|
499
|
-
end
|
500
|
-
|
501
|
-
|
502
452
|
def typed_id
|
503
453
|
"#{self.class.name.underscore}:#{self.id}" if id
|
504
454
|
end
|
@@ -4,10 +4,9 @@ module Hobo
|
|
4
4
|
|
5
5
|
include Hobo::Controller
|
6
6
|
|
7
|
-
VIEWLIB_DIR = "taglibs"
|
8
|
-
|
9
7
|
DONT_PAGINATE_FORMATS = [ Mime::CSV, Mime::YAML, Mime::JSON, Mime::XML, Mime::ATOM, Mime::RSS ]
|
10
|
-
|
8
|
+
|
9
|
+
WILL_PAGINATE_OPTIONS = [ :page, :per_page, :total_entries, :count, :finder ]
|
11
10
|
|
12
11
|
READ_ONLY_ACTIONS = [:index, :show]
|
13
12
|
WRITE_ONLY_ACTIONS = [:create, :update, :destroy]
|
@@ -27,7 +26,6 @@ module Hobo
|
|
27
26
|
|
28
27
|
helper_method :model, :current_user
|
29
28
|
before_filter :set_no_cache_headers
|
30
|
-
after_filter :remember_page_path
|
31
29
|
|
32
30
|
rescue_from ActiveRecord::RecordNotFound, :with => :not_found
|
33
31
|
|
@@ -35,7 +33,7 @@ module Hobo
|
|
35
33
|
rescue_from Hobo::Lifecycles::LifecycleKeyError, :with => :permission_denied
|
36
34
|
|
37
35
|
alias_method_chain :render, :hobo_model
|
38
|
-
|
36
|
+
|
39
37
|
end
|
40
38
|
register_controller(base)
|
41
39
|
|
@@ -97,7 +95,7 @@ module Hobo
|
|
97
95
|
index_action "complete_#{name}", &block
|
98
96
|
else
|
99
97
|
index_action "complete_#{name}" do
|
100
|
-
hobo_completions
|
98
|
+
hobo_completions field, model, options
|
101
99
|
end
|
102
100
|
end
|
103
101
|
end
|
@@ -109,8 +107,8 @@ module Hobo
|
|
109
107
|
got_block = block_given?
|
110
108
|
define_method web_name do
|
111
109
|
# Make sure we have a copy of the options - it is being mutated somewhere
|
112
|
-
opts =
|
113
|
-
self.this = find_instance(opts)
|
110
|
+
opts = options.dup
|
111
|
+
self.this = find_instance(opts)
|
114
112
|
raise Hobo::PermissionDeniedError unless @this.method_callable_by?(current_user, method)
|
115
113
|
if got_block
|
116
114
|
instance_eval(&block)
|
@@ -118,7 +116,7 @@ module Hobo
|
|
118
116
|
@this.send(method)
|
119
117
|
end
|
120
118
|
|
121
|
-
hobo_ajax_response
|
119
|
+
hobo_ajax_response unless performed?
|
122
120
|
end
|
123
121
|
end
|
124
122
|
|
@@ -370,7 +368,7 @@ module Hobo
|
|
370
368
|
after_submit = params[:after_submit]
|
371
369
|
|
372
370
|
# The after_submit post parameter takes priority
|
373
|
-
(after_submit == "stay-here" ?
|
371
|
+
(after_submit == "stay-here" ? url_for_page_path : after_submit) ||
|
374
372
|
|
375
373
|
# Then try the record's show page
|
376
374
|
(!destroyed && object_url(@this)) ||
|
@@ -385,6 +383,11 @@ module Hobo
|
|
385
383
|
home_page
|
386
384
|
end
|
387
385
|
|
386
|
+
|
387
|
+
def url_for_page_path
|
388
|
+
controller, view = Controller.controller_and_view_for(params[:page_path])
|
389
|
+
url_for :controller => controller, :action => view
|
390
|
+
end
|
388
391
|
|
389
392
|
# TODO: Get rid of this joke of an idea that fails miserably if you open another browser window.
|
390
393
|
def previous_page_path
|
@@ -410,10 +413,12 @@ module Hobo
|
|
410
413
|
|
411
414
|
def response_block(&b)
|
412
415
|
if b
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
416
|
+
respond_to do |format|
|
417
|
+
if b.arity == 1
|
418
|
+
yield format
|
419
|
+
else
|
420
|
+
format.html { yield }
|
421
|
+
end
|
417
422
|
end
|
418
423
|
performed?
|
419
424
|
end
|
@@ -421,7 +426,7 @@ module Hobo
|
|
421
426
|
|
422
427
|
|
423
428
|
def request_requires_pagination?
|
424
|
-
request.format.not_in?(DONT_PAGINATE_FORMATS)
|
429
|
+
request.format.not_in?(DONT_PAGINATE_FORMATS) && model.view_hints.paginate?
|
425
430
|
end
|
426
431
|
|
427
432
|
|
@@ -442,7 +447,7 @@ module Hobo
|
|
442
447
|
def find_owner_and_association(owner_association)
|
443
448
|
refl = model.reflections[owner_association]
|
444
449
|
klass = refl.klass
|
445
|
-
id = params["#{
|
450
|
+
id = params["#{owner_association}_id"]
|
446
451
|
owner = klass.find(id)
|
447
452
|
instance_variable_set("@#{owner_association}", owner)
|
448
453
|
[owner, owner.send(model.reverse_reflection(owner_association).name)]
|
@@ -470,7 +475,7 @@ module Hobo
|
|
470
475
|
|
471
476
|
def hobo_show(*args, &b)
|
472
477
|
options = args.extract_options!
|
473
|
-
self.this
|
478
|
+
self.this ||= find_instance(options)
|
474
479
|
response_block(&b)
|
475
480
|
end
|
476
481
|
|
@@ -490,7 +495,7 @@ module Hobo
|
|
490
495
|
|
491
496
|
def hobo_create(*args, &b)
|
492
497
|
options = args.extract_options!
|
493
|
-
self.this
|
498
|
+
self.this ||= args.first || new_for_create
|
494
499
|
this.user_update_attributes(current_user, options[:attributes] || attribute_parameters || {})
|
495
500
|
create_response(:new, &b)
|
496
501
|
end
|
@@ -499,7 +504,7 @@ module Hobo
|
|
499
504
|
def hobo_create_for(owner, *args, &b)
|
500
505
|
options = args.extract_options!
|
501
506
|
owner, association = find_owner_and_association(owner)
|
502
|
-
self.this
|
507
|
+
self.this ||= args.first || association.new
|
503
508
|
this.user_update_attributes(current_user, options[:attributes] || attribute_parameters || {})
|
504
509
|
create_response(:"new_for_#{owner}", &b)
|
505
510
|
end
|
@@ -547,7 +552,7 @@ module Hobo
|
|
547
552
|
def hobo_update(*args, &b)
|
548
553
|
options = args.extract_options!
|
549
554
|
|
550
|
-
self.this
|
555
|
+
self.this ||= args.first || find_instance
|
551
556
|
changes = options[:attributes] || attribute_parameters or raise RuntimeError, "No update specified in params"
|
552
557
|
this.user_update_attributes(current_user, changes)
|
553
558
|
|
@@ -594,7 +599,7 @@ module Hobo
|
|
594
599
|
|
595
600
|
def hobo_destroy(*args, &b)
|
596
601
|
options = args.extract_options!
|
597
|
-
self.this
|
602
|
+
self.this ||= args.first || find_instance
|
598
603
|
this.user_destroy(current_user)
|
599
604
|
flash[:notice] = "The #{model.name.titleize.downcase} was deleted" unless request.xhr?
|
600
605
|
destroy_response(&b)
|
@@ -671,7 +676,7 @@ module Hobo
|
|
671
676
|
options = options.reverse_merge(:limit => 10, :param => :query, :query_scope => "#{attribute}_contains")
|
672
677
|
finder = finder.limit(options[:limit]) unless finder.send(:scope, :find, :limit)
|
673
678
|
finder = finder.send(options[:query_scope], params[options[:param]])
|
674
|
-
items = finder.find(:all)
|
679
|
+
items = finder.find(:all).select { |r| r.viewable_by?(current_user) }
|
675
680
|
render :text => "<ul>\n" + items.map {|i| "<li>#{i.send(attribute)}</li>\n"}.join + "</ul>"
|
676
681
|
end
|
677
682
|
|
@@ -694,6 +699,7 @@ module Hobo
|
|
694
699
|
|
695
700
|
def permission_denied(error)
|
696
701
|
self.this = true # Otherwise this gets sent user_view
|
702
|
+
@permission_error = error
|
697
703
|
if "permission_denied".in?(self.class.superclass.instance_methods)
|
698
704
|
super
|
699
705
|
else
|
@@ -762,13 +768,6 @@ module Hobo
|
|
762
768
|
headers["Expires"] ='0'
|
763
769
|
end
|
764
770
|
|
765
|
-
def remember_page_path
|
766
|
-
if request.method == :get
|
767
|
-
session[:previous_page_path] = request.path
|
768
|
-
session[:previous_page_path] += "?#{request.query_string}" unless request.query_string.blank?
|
769
|
-
end
|
770
|
-
end
|
771
|
-
|
772
771
|
# --- end filters --- #
|
773
772
|
|
774
773
|
public
|
data/lib/hobo/model_router.rb
CHANGED
@@ -73,20 +73,23 @@ module Hobo
|
|
73
73
|
return
|
74
74
|
end
|
75
75
|
|
76
|
-
|
77
|
-
|
76
|
+
begin
|
77
|
+
require "#{RAILS_ROOT}/app/controllers/application" unless Object.const_defined? :ApplicationController
|
78
|
+
rescue MissingSourceFile => ex
|
79
|
+
# must be on Rails 2.3. Yay!
|
80
|
+
end
|
81
|
+
|
78
82
|
# Add non-subsite, and all subsite routes
|
79
83
|
[nil, *Hobo.subsites].each { |subsite| add_routes_for(map, subsite) }
|
80
84
|
|
81
85
|
add_developer_routes(map) if Hobo.developer_features?
|
82
86
|
|
83
|
-
# Run the DRYML generators
|
84
|
-
# TODO: This needs a proper home
|
85
|
-
Hobo::Dryml::DrymlGenerator.run unless caller[-1] =~ /[\/\\]rake:\d+$/
|
86
87
|
rescue ActiveRecord::StatementInvalid => e
|
87
88
|
# Database problem? Just continue without routes
|
88
|
-
ActiveRecord::Base.logger
|
89
|
-
|
89
|
+
if ActiveRecord::Base.logger
|
90
|
+
ActiveRecord::Base.logger.warn "!! Database exception during Hobo routing -- continuing without routes"
|
91
|
+
ActiveRecord::Base.logger.warn "!! #{e.to_s}"
|
92
|
+
end
|
90
93
|
end
|
91
94
|
|
92
95
|
|
@@ -132,11 +135,7 @@ module Hobo
|
|
132
135
|
|
133
136
|
|
134
137
|
def add_routes
|
135
|
-
|
136
|
-
if model < Hobo::CompositeModel
|
137
|
-
map.connect "#{plural}/:id", :controller => plural, :action => 'show', :requirements => ID_REQUIREMENT
|
138
|
-
|
139
|
-
elsif controller < Hobo::ModelController
|
138
|
+
if controller < Hobo::ModelController
|
140
139
|
# index routes need to be first so the index names don't get
|
141
140
|
# taken as IDs
|
142
141
|
index_action_routes
|
@@ -181,7 +180,7 @@ module Hobo
|
|
181
180
|
|
182
181
|
owner = owner.to_s.singularize if model.reflections[owner].macro == :has_many
|
183
182
|
|
184
|
-
collection_path = "#{owner_class.pluralize}/:#{
|
183
|
+
collection_path = "#{owner_class.pluralize}/:#{owner}_id/#{collection}"
|
185
184
|
|
186
185
|
actions.each do |action|
|
187
186
|
case action
|
data/lib/hobo/permissions.rb
CHANGED
@@ -319,68 +319,78 @@ module Hobo
|
|
319
319
|
|
320
320
|
# By default, attempt to derive edit permission from create/update permission
|
321
321
|
def edit_permitted?(attribute)
|
322
|
-
if attribute
|
323
|
-
with_attribute_or_belongs_to_keys(attribute) do |attr, ftype|
|
324
|
-
unknownify_attribute(self, attr)
|
325
|
-
unknownify_attribute(self, ftype) if ftype
|
326
|
-
end
|
327
|
-
end
|
322
|
+
unknownify_attribute(attribute) if attribute
|
328
323
|
new_record? ? create_permitted? : update_permitted?
|
329
324
|
rescue Hobo::UndefinedAccessError
|
330
325
|
# The permission is dependent on the unknown value
|
331
326
|
# so this attribute is not editable
|
332
327
|
false
|
333
328
|
ensure
|
334
|
-
if attribute
|
335
|
-
with_attribute_or_belongs_to_keys(attribute) do |attr, ftype|
|
336
|
-
deunknownify_attribute(self, attr)
|
337
|
-
deunknownify_attribute(self, ftype) if ftype
|
338
|
-
end
|
339
|
-
end
|
329
|
+
deunknownify_attribute(attribute) if attribute
|
340
330
|
end
|
341
331
|
|
342
332
|
|
343
333
|
# Add some singleton methods to +record+ so give the effect that +attribute+ is unknown. That is,
|
344
334
|
# attempts to access the attribute will result in a Hobo::UndefinedAccessError
|
345
|
-
def unknownify_attribute(
|
346
|
-
|
347
|
-
|
335
|
+
def unknownify_attribute(attr)
|
336
|
+
metaclass.class_eval do
|
348
337
|
define_method attr do
|
349
338
|
raise Hobo::UndefinedAccessError
|
350
339
|
end
|
340
|
+
end
|
341
|
+
|
342
|
+
if (refl = self.class.reflections[attr.to_sym]) && refl.macro == :belongs_to
|
343
|
+
# A belongs_to -- also unknownify the underlying fields
|
344
|
+
unknownify_attribute refl.primary_key_name
|
345
|
+
unknownify_attribute refl.options[:foreign_type] if refl.options[:polymorphic]
|
346
|
+
else
|
347
|
+
# A regular field -- hack the dirty tracking methods
|
351
348
|
|
352
|
-
|
353
|
-
raise Hobo::UndefinedAccessError
|
354
|
-
end
|
349
|
+
metaclass.class_eval do
|
355
350
|
|
356
|
-
|
357
|
-
|
358
|
-
|
351
|
+
define_method "#{attr}_change" do
|
352
|
+
raise Hobo::UndefinedAccessError
|
353
|
+
end
|
359
354
|
|
360
|
-
|
361
|
-
|
362
|
-
|
355
|
+
define_method "#{attr}_was" do
|
356
|
+
read_attribute attr
|
357
|
+
end
|
358
|
+
|
359
|
+
define_method "#{attr}_changed?" do
|
360
|
+
true
|
361
|
+
end
|
363
362
|
|
364
|
-
|
365
|
-
|
366
|
-
|
363
|
+
def changed?
|
364
|
+
true
|
365
|
+
end
|
367
366
|
|
368
|
-
|
369
|
-
|
370
|
-
|
367
|
+
define_method :changed do
|
368
|
+
changed_attributes.keys | [attr.to_s]
|
369
|
+
end
|
371
370
|
|
372
|
-
|
373
|
-
|
374
|
-
|
371
|
+
def changes
|
372
|
+
raise Hobo::UndefinedAccessError
|
373
|
+
end
|
375
374
|
|
375
|
+
end
|
376
376
|
end
|
377
|
-
|
378
377
|
end
|
379
378
|
|
380
379
|
# Best. Name. Ever
|
381
|
-
def deunknownify_attribute(
|
382
|
-
|
383
|
-
|
380
|
+
def deunknownify_attribute(attr)
|
381
|
+
attr = attr.to_sym
|
382
|
+
|
383
|
+
metaclass.send :remove_method, attr
|
384
|
+
|
385
|
+
if (refl = self.class.reflections[attr]) && refl.macro == :belongs_to
|
386
|
+
# A belongs_to -- restore the underlying fields
|
387
|
+
deunknownify_attribute refl.primary_key_name
|
388
|
+
deunknownify_attribute refl.options[:foreign_type] if refl.options[:polymorphic]
|
389
|
+
else
|
390
|
+
# A regular field -- restore the dirty tracking methods
|
391
|
+
["#{attr}_change", "#{attr}_was", "#{attr}_changed?", :changed?, :changed, :changes].each do |m|
|
392
|
+
metaclass.send :remove_method, m.to_sym
|
393
|
+
end
|
384
394
|
end
|
385
395
|
end
|
386
396
|
end
|