composed_of freezes objects but if my object requires validations ie
class MyObject
validate do |record|
if fail?
record.errors.add :base, “FAIL!”
end
end
end
class Foo < ActiveRecord::Base
composed_of :my_object,
:allow_nil => true,
:mapping => [
%w[bgmd_name name],
%w[bgmd_serial_number serial_number]
]
validates_associated :my_object
end
this borks with a object is frozen error deep in
lib/active_model/validations.rb
I’ve got a work around
module MySugr
This module is mainly a hack to get around a bug with composed_of
freezing objects
and ActiveRecord::Validations requiring unfrozen objects
module Composable
def self.included(base)
base.send :extend, ClassMethods
base.send :include, ActiveRecord::Validations
base.send :include, InstanceMethods
base.send :define_method, :"validation_context=" do |*args|
end
end
module InstanceMethods
def initialize(*args)
errors
end
def new_record?
true
end
end
module ClassMethods
end
end
end
which I can mix into my class but it is not ideal. How to report a rails
bug? The lighthouse
tracker seems invite only these days?
Brad
And I’m using Rails 3.1 RC1!
On Jun 6, 3:38pm, Brad P. [email protected] wrote:
class Foo < ActiveRecord::Base
end
module Composable
module InstanceMethods
module ClassMethods
end
end
end
which I can mix into my class but it is not ideal. How to report a rails
bug? The lighthouse
tracker seems invite only
Rails moved to using github issues recently.
I believe validates_associated with was intended to be used with
associations rather than aggregations. You might find validates_with
useful
Fred
validates_with is not really the solution. Aggregations are semantically
the
same as has_one relations and should be able to validate
the same as.
Looks like somebody closed the issue on github after importing from
lighthouse without solving the issue
opened 03:57AM - 16 May 11 UTC
closed 03:12PM - 21 May 11 UTC
_Imported from Lighthouse._ Original ticket at: http://rails.lighthouseapp.com/p… rojects/8994/tickets/5646
Created by **Jamie** - 2011-02-19 09:28:29 UTC
Steps to reproduce:
- Create a value object using composed_of like in the Rails documentation. Use the :converter option to recreate the value object from the params hash when attributes= is called on the parent.
- Add validations to the value object.
- Run those validations by using validates_associated in the entity where you have composed_of.
What happens:
- A 'can't modify frozen object' error is thrown.
Why it happens:
- Not really sure, but I tracked it as far as the valid? method in ActiveRecord::Validations. It appears to break in the "ensure" part of the that method. This was added in commit 82485068f8b64a49cbb6. When I overrode valid? in my value object, using the logic as it was before that commit, validates_associated started working as expected.
or explaining why it will not be solved.
On Jun 6, 7:07pm, Brad P. [email protected] wrote:
validates_with is not really the solution. Aggregations are semantically the
same as has_one relations and should be able to validate
the same as.
Looks like somebody closed the issue on github after importing from
lighthouse without solving the issue
validates_associated throws 'can't modify frozen object' error · Issue #727 · rails/rails · GitHub
or explaining why it will not be solved.
Not sure I agree.
All the imported issues were closed automatically at some point - it
wasn’t a reflection on the merit of those issues
Fred
I guess I’ll open it up again then
I opened a github ticket on this issue
opened 07:50PM - 06 Jun 11 UTC
closed 02:14AM - 19 Jun 12 UTC
activemodel
composed_of objects should be able to take advantage of ActiveModel::Validations… . However composed_of uses value
semantics and freezes the objects.
The solution is to ensure that ActiveModel::Validations use variables with "reference" semantics so that if the object is frozen you can still add errors to the validation. The following monkey patch works for me and doesn't add any performance overhead or space overhead for creating Errors objects if they are not needed.
```
module ActiveModel
module Validations
def self.included(base)
super base
base.class_eval do
def errors
@errors ||= []
@errors[0] ||= ActiveModel::Errors.new(self)
@errors[0]
end
def validation_context=(val)
@validation_context ||= []
@validation_context[0] = val
end
def validation_context
@validation_context ||= []
@validation_context[0]
end
def freeze
@errors ||= []
@validation_context ||= []
super
end
end
end
end
end
module MySugr
# This module is mainly a hack to get around a bug with composed_of freezing objects
# and ActiveRecord::Validations requiring unfrozen objects
module Composable
def self.included(base)
base.send :include, ActiveModel::Validations
end
def new_record?
true
end
end
end
```
and is used like
```
class BolusPumpSetting
include MySugr::Composable
attr_reader :normal_units, :square_units, :square_duration
def initialize(normal_units, square_units, square_duration)
@normal_units = normal_units
@square_units = square_units
@square_duration = square_duration
end
validate do |record|
if record.square_units.nil? ^ record.square_duration.nil?
record.errors.add :base, "Must set both square_units and square duration"
end
end
end
```
```
class Log < ActiveRecord::Base
composed_of :bolus_pump_setting,
:allow_nil => true,
:mapping => [
%w[bolus_pump_setting_normal_units normal_units],
%w[bolus_pump_setting_square_units square_units],
%w[bolus_pump_setting_square_duration square_duration]
]
validates_associated :bolus_pump_setting
end
```