Skip to content

Instantly share code, notes, and snippets.

@openfirmware
Created June 14, 2010 16:54
Show Gist options
  • Save openfirmware/437939 to your computer and use it in GitHub Desktop.
Save openfirmware/437939 to your computer and use it in GitHub Desktop.
# Potential solution to "Using accepts_nested_attributes_for with a belongs_to association, and using find_or_create_by_attr behaviour"
# http://stackoverflow.com/questions/2970255/using-accepts-nested-attributes-for-with-a-belongs-to-association-and-using-find
class Upload < AR:B
belongs_to :user
belongs_to :observed_property
belongs_to :sensor
attr_accessor :observed_property_attributes,
:sensor_attributes
attr_accessible :observed_property_attributes,
:sensor_attributes
validate :validate_associations
def before_validation
unless (@observed_property_attributes && @sensor_attributes)
false
else
update_associations
end
end
def update_associations
creator = User.find(self.user_id)
observed_property = ObservedProperty.find_by_name(@observed_property_attributes[:name])
if observed_property.nil?
observed_property = creator.observed_properties.build(@observed_property_attributes)
end
self.observed_property = observed_property
sensor = Sensor.find_by_name(@sensor_attributes[:name])
if sensor.nil?
sensor = creator.sensors.build(@sensor_attributes)
end
self.sensor = sensor
end
def validate_associations
merge_errors(observed_property) unless self.observed_property.valid?
merge_errors(sensor) unless self.sensor.valid?
end
def merge_errors(instance)
instance.errors.each do |att, msg|
if att == 'base'
errors.add(instance.class, msg)
else
errors.add("#{instance.class}_#{att}", msg)
end
end
end
end
# Matching spec
# spec_helper.rb defines a few sample users
require 'spec_helper'
describe Upload do
before(:each) do
@valid_attributes = {
:observed_property_attributes => Factory.attributes_for(:observed_property, :creator => @user_a),
:sensor_attributes => Factory.attributes_for(:sensor, :creator => @user_a)
}
end
it "should create a new instance given valid attributes" do
upload = @user_a.uploads.create!(@valid_attributes)
upload.observed_property.should_not be_nil
upload.sensor.should_not be_nil
end
it "should use existing models when linked to them, regardless of creator" do
observed_property = Factory :observed_property, :creator => @user_b
sensor = Factory :sensor, :creator => @user_c
upload = @user_a.uploads.create!(
:observed_property_attributes => { :_id => observed_property._id },
:sensor_attributes => { :_id => sensor._id }
)
upload.observed_property.should == observed_property
upload.sensor.should == sensor
end
it "should not save with blank attributes" do
upload = @user_a.uploads.new
upload.observed_property = ObservedProperty.new
upload.sensor = Sensor.new
upload.update_attributes(
:observed_property_attributes => {
:_id => "",
:unit => "",
:description => ""
},
:sensor_attributes => {
:_id => "",
:description => ""
}
)
lambda {
upload.save!
}.should raise_error
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment