Module: RemoteAssociation::BelongsToRemote

Included in:
RemoteAssociation::Base::ClassMethods
Defined in:
lib/remote_association/belongs_to_remote.rb

Instance Method Summary collapse

Instance Method Details

#belongs_to_remote(remote_rel, options = {}) ⇒ Object

Specifies a one-to-one association with another class. This method should only be used if this class contains the foreign key. If the other class contains the foreign key, then you should use has_one_remote instead.

Methods will be added for retrieval and query for a single associated object, for which this object holds an id:

association

Returns the associated object. nil is returned if none is found. When foreign_key value is nil, remote request would not be executed.

association=(associate)

Just setter, no saves.

(association is replaced with the symbol passed as the first argument, so belongs_to_remote :author would add among others author.nil?.)

Example

A Post class declares belongs_to_remote :author, which will add:

  • Post#author (similar to Author.find(:first, params: { id: [post.author_id]}))

  • Post#author=(author) (will set @author instance variable of Post# to author value)

The declaration can also include an options hash to specialize the behavior of the association.

Options

:class_name

Specify the class name of the association. Use it only if that name can’t be inferred from the association name. So belongs_to_remote :author will by default be linked to the Author class, but if the real class name is Person, you’ll have to specify it with this option.

:foreign_key

Specify the foreign key used for the association. By default this is guessed to be the name of the association with an “_id” suffix. So a class that defines a belongs_to_remote :person association will use “person_id” as the default :foreign_key. Similarly, belongs_to_remote :favorite_person, :class_name => "Person" will use a foreign key of “favorite_person_id”.

:primary_key

Specify the http query parameter to find associated object used for the association. By default this is id.

:polymorphic

Specify this association is a polymorphic association by passing true.

:foreign_type

Specify the column used to store the associated object’s type, if this is a polymorphic association. By default this is guessed to be the name of the association with a “_type” suffix. So a class that defines a belongs_to_remote :owner, :polymorphic => true association will use “owner_type” as the default :foreign_type. Example:

belongs_to_remote :firm, :primary_key => 'search[id_in]' #=> ...?firms.json?search%5Bid_in%5D%5B%5D=1

Option examples:

belongs_to_remote :firm, :foreign_key => "client_of"
belongs_to_remote :author, :class_name => "Person", :foreign_key => "author_id"


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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/remote_association/belongs_to_remote.rb', line 53

def belongs_to_remote(remote_rel, options ={})
  rel_options = {
                 class_name:    remote_rel.to_s.classify,
                 foreign_key:   remote_rel.to_s.foreign_key,
                 foreign_type:  remote_rel.to_s + '_type',
                 association_type: :belongs_to_remote,
                 primary_key: primary_key
                }.merge(options.symbolize_keys)

  add_activeresource_relation(remote_rel.to_sym, rel_options)

  if rel_options[:polymorphic]
    class_eval <<-RUBY, __FILE__, __LINE__+1

      attr_accessor :#{remote_rel}

      def #{remote_rel}
        if remote_resources_loaded?
          @#{remote_rel} ? @#{remote_rel}.first : nil
        else
          @#{remote_rel} ||= if self.#{rel_options[:foreign_key]}.present? && self.#{rel_options[:foreign_class]}.present?
                               #{rel_options[:foreign_type]}.classify.constantize.find(:all, params: self.class.build_params_hash_for_#{remote_rel}(self.#{rel_options[:foreign_key]})).try(:first)
                             else
                               nil
                             end
        end
      end

      ##
      # Returns Hash with HTTP parameters to query remote API
      def self.build_params_hash_for_#{remote_rel}(keys)
        keys = [keys] unless keys.kind_of?(Array)
        {"#{rel_options[:primary_key]}" => keys}
      end

    RUBY
  else
    class_eval <<-RUBY, __FILE__, __LINE__+1

      attr_accessor :#{remote_rel}

      def #{remote_rel}
        if remote_resources_loaded?
          @#{remote_rel} ? @#{remote_rel}.first : nil
        else
          @#{remote_rel} ||= if self.#{rel_options[:foreign_key]}.present?
                               #{rel_options[:class_name]}.find(:all, params: self.class.build_params_hash_for_#{remote_rel}(self.#{rel_options[:foreign_key]})).try(:first)
                             else
                               nil
                             end
        end
      end

      ##
      # Returns Hash with HTTP parameters to query remote API
      def self.build_params_hash_for_#{remote_rel}(keys)
        keys = [keys] unless keys.kind_of?(Array)
        {"#{rel_options[:primary_key]}" => keys}
      end

    RUBY
  end
end