Module: AttrJson::NestedAttributes
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/attr_json/nested_attributes.rb,
lib/attr_json/nested_attributes/writer.rb,
lib/attr_json/nested_attributes/builder.rb,
lib/attr_json/nested_attributes/multiparameter_attribute_writer.rb
Overview
The implementation is based on ActiveRecord::NestedAttributes, from https://github.com/rails/rails/blob/a45f234b028fd4dda5338e5073a3bf2b8bf2c6fd/activerecord/lib/active_record/nested_attributes.rb
Re-used, and customized/overrode methods to match our implementation. Copied over some implementation so we can use in ActiveModel's that original isn't compatible with. The original is pretty well put together and has had very low churn history.
Much of the AR implementation, copied, just works,
if we define '#{attribute_name}_attributes='
methods that work. That's mostly what
we have to do here.
Unlike AR, we try to put most of our implementation in seperate implementation helper instances, instead of adding a bazillion methods to the model itself.
Defined Under Namespace
Classes: Builder, MultiparameterAttributeWriter, Writer
Class Method Summary collapse
-
.attr_json_accepts_nested_attributes_for(define_build_method: true, reject_if: nil, limit: nil) ⇒ Object
Much like ActiveRecord
accepts_nested_attributes_for
, but used with embedded AttrJson::Model-type attributes (single or array).
Class Method Details
.attr_json_accepts_nested_attributes_for(define_build_method: true, reject_if: nil, limit: nil) ⇒ Object
Much like ActiveRecord accepts_nested_attributes_for
, but used with embedded
AttrJson::Model-type attributes (single or array). See doc page on Forms support.
Note some AR options are not supported.
- allow_destroy, no such option. Effectively always true, doesn't make sense to try to gate this with our implementation.
- update_only, no such option. Not really relevant to this architecture where you're embedded models have no independent existence.
If called on an array of 'primitive' (not AttrJson::Model) objects, it will do a kind of weird
thing where it creates an #{attribute_name}_attributes=
method that does nothing
but filter out empty strings and nil values. This can be convenient in hackily form
handling array of primitives, see guide doc on forms.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/attr_json/nested_attributes.rb', line 49 def attr_json_accepts_nested_attributes_for(*attr_names) = { define_build_method: true } .update(attr_names.) .assert_valid_keys(:reject_if, :limit, :define_build_method) [:reject_if] = ActiveRecord::NestedAttributes::ClassMethods::REJECT_ALL_BLANK_PROC if [:reject_if] == :all_blank unless respond_to?(:nested_attributes_options) # Add it when we're in a AttrJson::Model. In an ActiveRecord::Base we'll just use the # existing one, it'll be okay. # https://github.com/rails/rails/blob/c14deceb9f36f82cd5ca3db214d85e1642eb0bfd/activerecord/lib/active_record/nested_attributes.rb#L16 class_attribute :nested_attributes_options, instance_writer: false self. ||= {} end attr_names.each do |attr_name| attr_def = attr_json_registry[attr_name] unless attr_def raise ArgumentError, "No attr_json found for name '#{attr_name}'. Has it been defined yet?" end unless attr_def.array_type? || attr_def.single_model_type? raise TypeError, "attr_json_accepts_nested_attributes_for is only for array or nested model types; `#{attr_name}` is type #{attr_def.type.type.inspect}" end # We're sharing AR class attr in an AR, or using our own in a Model. = self..dup [attr_name.to_sym] = self. = _attr_jsons_module.module_eval do if method_defined?(:"#{attr_name}_attributes=") remove_method(:"#{attr_name}_attributes=") end define_method "#{attr_name}_attributes=" do |attributes| Writer.new(self, attr_name).assign_nested_attributes(attributes) end end # No build method for our wacky array of primitive type. if [:define_build_method] && !attr_def.array_of_primitive_type? _attr_jsons_module.module_eval do build_method_name = "build_#{attr_name.to_s.singularize}" if method_defined?(build_method_name) remove_method(build_method_name) end define_method build_method_name do |params = {}| Builder.new(self, attr_name).build(params) end end end end end |