forked from rails/rails
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for associating unsaved objects rails#402 [Tim Bates]
Added replace to associations, so you can do project.manager.replace(new_manager) or project.milestones.replace(new_milestones) rails#402 [Tim Bates] Added build and create methods to has_one and belongs_to associations, so you can now do project.manager.build(attributes) rails#402 [Tim Bates] Fixed that Base#== wouldn't work for multiple references to the same unsaved object rails#402 [Tim Bates] Added that if a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks defined as methods on the model, which are called last. rails#402 [Tim Bates] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@417 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
- Loading branch information
Showing
15 changed files
with
800 additions
and
307 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
activerecord/lib/active_record/associations/association_proxy.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
module ActiveRecord | ||
module Associations | ||
class AssociationProxy #:nodoc: | ||
alias_method :proxy_respond_to?, :respond_to? | ||
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?|^proxy_respond_to\?|^send)/ } | ||
|
||
def initialize(owner, association_name, association_class_name, association_class_primary_key_name, options) | ||
@owner = owner | ||
@options = options | ||
@association_name = association_name | ||
@association_class = eval(association_class_name) | ||
@association_class_primary_key_name = association_class_primary_key_name | ||
|
||
reset | ||
end | ||
|
||
def method_missing(symbol, *args, &block) | ||
load_target | ||
@target.send(symbol, *args, &block) | ||
end | ||
|
||
def respond_to?(symbol, include_priv = false) | ||
load_target | ||
proxy_respond_to?(symbol, include_priv) || @target.respond_to?(symbol, include_priv) | ||
end | ||
|
||
def loaded? | ||
@loaded | ||
end | ||
|
||
private | ||
def load_target | ||
unless @owner.new_record? | ||
begin | ||
@target = find_target if not loaded? | ||
rescue ActiveRecord::RecordNotFound | ||
reset | ||
end | ||
end | ||
@loaded = true | ||
@target | ||
end | ||
|
||
def raise_on_type_mismatch(record) | ||
raise ActiveRecord::AssociationTypeMismatch, "#{@association_class} expected, got #{record.class}" unless record.is_a?(@association_class) | ||
end | ||
end | ||
end | ||
end |
70 changes: 70 additions & 0 deletions
70
activerecord/lib/active_record/associations/belongs_to_association.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
module ActiveRecord | ||
module Associations | ||
class BelongsToAssociation < AssociationProxy #:nodoc: | ||
|
||
def reset | ||
@target = nil | ||
@loaded = false | ||
end | ||
|
||
def reload | ||
reset | ||
load_target | ||
end | ||
|
||
def create(attributes = {}) | ||
record = build(attributes) | ||
record.save | ||
record | ||
end | ||
|
||
def build(attributes = {}) | ||
record = @association_class.new(attributes) | ||
replace(record, true) | ||
record | ||
end | ||
|
||
def replace(obj, dont_save = false) | ||
if obj.nil? | ||
@target = @owner[@association_class_primary_key_name] = nil | ||
else | ||
raise_on_type_mismatch(obj) unless obj.nil? | ||
|
||
@target = obj | ||
@owner[@association_class_primary_key_name] = obj.id unless obj.new_record? | ||
end | ||
@loaded = true | ||
end | ||
|
||
# Ugly workaround - .nil? is done in C and the method_missing trick doesn't work when we pretend to be nil | ||
def nil? | ||
load_target | ||
@target.nil? | ||
end | ||
|
||
private | ||
def find_target | ||
if @options[:conditions] | ||
@association_class.find_on_conditions(@owner[@association_class_primary_key_name], @options[:conditions]) | ||
else | ||
@association_class.find(@owner[@association_class_primary_key_name]) | ||
end | ||
end | ||
|
||
def target_obsolete? | ||
@owner[@association_class_primary_key_name] != @target.id | ||
end | ||
|
||
def construct_sql | ||
# no sql to construct | ||
end | ||
end | ||
end | ||
end | ||
|
||
class NilClass #:nodoc: | ||
# Ugly workaround - nil comparison is usually done in C and so a proxy object pretending to be nil doesn't work. | ||
def ==(other) | ||
other.nil? | ||
end | ||
end |
Oops, something went wrong.