module Restorm module Model module Associations class Association # @private attr_accessor :params # @private def initialize(parent, opts = {}) @parent = parent @opts = opts @params = {} @klass = @parent.class.restorm_nearby_class(@opts[:class_name]) @name = @opts[:name] end # @private def self.proxy(parent, opts = {}) AssociationProxy.new new(parent, opts) end # @private def self.parse_single(association, klass, data) data_key = association[:data_key] return {} unless data[data_key] klass = klass.restorm_nearby_class(association[:class_name]) { association[:name] => klass.instantiate_record(klass, data: data[data_key]) } end # @private def assign_single_nested_attributes(attributes) if @parent.attributes[@name].blank? @parent.attributes[@name] = @klass.new(@klass.parse(attributes)) else @parent.attributes[@name].assign_attributes(attributes) end end # @private def fetch(opts = {}) attribute_value = @parent.attributes[@name] return @opts[:default].try(:dup) if @parent.attributes.include?(@name) && (attribute_value.nil? || !attribute_value.nil? && attribute_value.empty?) && @params.empty? return @cached_result unless @params.any? || @cached_result.nil? return @parent.attributes[@name] unless @params.any? || @parent.attributes[@name].blank? return @opts[:default].try(:dup) if @parent.new? path = build_association_path -> { "#{@parent.request_path(@params)}#{@opts[:path]}" } @klass.get(path, @params).tap do |result| @cached_result = result unless @params.any? end end # @private def build_association_path(code) instance_exec(&code) rescue Restorm::Errors::PathError nil end # @private def reset @params = {} @cached_result = nil @parent.attributes.delete(@name) end # Add query parameters to the HTTP request performed to fetch the data # # @example # class User # include Restorm::Model # has_many :comments # end # # user = User.find(1) # user.comments.where(:approved => 1) # Fetched via GET "/users/1/comments?approved=1 def where(params = {}) return self if params.blank? && @parent.attributes[@name].blank? AssociationProxy.new clone.tap { |a| a.params = a.params.merge(params) } end alias all where # Fetches the data specified by id # # @example # class User # include Restorm::Model # has_many :comments # end # # user = User.find(1) # user.comments.find(3) # Fetched via GET "/users/1/comments/3 def find(id) return nil if id.blank? path = build_association_path -> { "#{@parent.request_path(@params)}#{@opts[:path]}/#{id}" } @klass.get_resource(path, @params) end # Refetches the association and puts the proxy back in its initial state, # which is unloaded. Cached associations are cleared. # # @example # class User # include Restorm::Model # has_many :comments # end # # class Comment # include Restorm::Model # end # # user = User.find(1) # user.comments = [#] # user.comments.first.id = "Oops" # user.comments.reload # => [#] # # Fetched again via GET "/users/1/comments" def reload reset fetch end end end end end