Module: Daylight::Associations::ClassMethods

Defined in:
lib/daylight/associations.rb

Instance Method Summary collapse

Instance Method Details

#belongs_to(name, options = {}) ⇒ Object

Adds a setter to the original ‘belongs_to` method that uses nested_attributes. Also, hands off the :through option to `belongs_to_through`.

Example:

comment = Comment.find(1)
comment.creator = current_user

See: ActiveResource::Associations#belongs_to



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/daylight/associations.rb', line 94

def belongs_to name, options={}
  create_reflection(:belongs_to, name, options).tap do |reflection|

    nested_attribute_key = "#{reflection.name}_attributes"

    # setup the resource_proxy to fetch the results
    define_cached_method reflection.name, cache_key: nested_attribute_key do
      reflection.klass.find(send(reflection.foreign_key))
    end

    # Defines a setter caching the value in an instance variable for later
    # retrieval.  Stash value directly in the attributes using the
    # nested_attributes functionality server-side.
    define_method "#{reflection.name}=" do |value|
      attributes[reflection.foreign_key] = value.id           # set the foreign key
      instance_variable_set(:"@#{reflection.name}", value)    # set the cached value
    end
  end
end

#has_many(name, options = {}) ⇒ Object

Support for the :through option so that the server-side handles the association.

Post.first.comments #=> GET /posts/1/comments.json

Also adds the setter for assocations:

Post.first.comments = [new_comment]

See: ActiveResource::Associations#has_many



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/daylight/associations.rb', line 57

def has_many name, options={}
  through = options.delete(:use).to_s
  return super if through == 'resource'

  create_reflection(:has_many, name, options).tap do |reflection|
    nested_attribute_key = "#{reflection.name}_attributes"

    # setup the resource_proxy to fetch the results
    define_cached_method reflection.name, cache_key: nested_attribute_key do
      # return a empty collection if this is a new record
      return self.send("#{reflection.name}=", []) if new?

      resource_proxy = resource_proxy_for(reflection, self)
      resource_proxy.from(association_path(reflection))
    end

    # define setter that places the value directly in the attributes using
    # the nested_attributes functionality server-side
    define_method "#{reflection.name}=" do |value|
      instance_variable_set(:"@#{reflection.name}", value)
    end

  end
end

#has_one(name, options = {}) ⇒ Object

Fix bug in has_one that is not creating the request correctly. Use ‘where` functionality as it peforms the function that is needed

Allows the has_one :through association.

See: has_one_through



196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/daylight/associations.rb', line 196

def has_one(name, options = {})
  return has_one_through(name, options) if options.has_key? :through

  create_reflection(:has_one, name, options).tap do |reflection|
    define_cached_method reflection.name do
      reflection.klass.where(:"#{self.class.element_name}_id" => self.id).first
    end

    define_method "#{reflection.name}=" do |value|
      value.attributes[:"#{self.class.element_name}_id"] = self.id
      instance_variable_set(:"@#{reflection.name}", value)    # set the cached value
    end
  end
end

#has_one_through(name, options) ⇒ Object

Adds getter and setter methods for ‘has_one` associations that are through a `belongs_to` association. Assumes that the information about the association is generated in the nested attributes by a HasOneThrough serializer.

In this example, if we did not go through the identity association the primary keys would be generated, but upon save, an error would be thrown because it is an unknown attribute. This only happens with ‘belongs_to` methods as they contain the primary_key.

For example, consider ‘user_id` and `zone_id` primary keys:

class PostSerializer < ActiveModel::Serializer
  embed :ids

  has_one :blog
  has_one :company, :zone through: :blog
 end

It will generate the following json:

{
  "post": {
    "id": 1,
    "blog_id": 2,
    "blog_attributes": {
      "id": 2,
      "company_id": 3
    }
  }
}

An ActiveResource can define ‘belongs_to` with :through to read from nested attributes for fetching by primary_key or setting to save.

 class Post < Daylight::API
   belongs_to :blog
   has_one    :company, through: :blog
 end

So that:

 p = Post.find(1)
 p.blog      # => #<Blog @attributes={"id"=>1}>
 p.company   # => #<Company @attributes={"id"=>3}>

And setting these associations will work with passing validations:

 p.company = Company.find(1)
 p.save  # => true


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/daylight/associations.rb', line 166

def has_one_through name, options
  through = options.delete(:through).to_s

  create_reflection(:has_one, name, options).tap do |reflection|
    nested_attributes_key  = "#{reflection.name}_attributes"
    through_attributes_key = "#{through}_attributes"

    define_cached_method reflection.name, index: through_attributes_key do
      reflection.klass.find(attributes[through_attributes_key][reflection.foreign_key])
    end

    define_method "#{reflection.name}=" do |value|
      through_attributes = attributes["#{through}_attributes"] ||= {}

      through_attributes[reflection.foreign_key] = value.id
      through_attributes[nested_attributes_key]  = value
      instance_variable_set(:"@#{reflection.name}", value)
    end
  end
end

#reflection_namesObject



41
42
43
# File 'lib/daylight/associations.rb', line 41

def reflection_names
  reflections.keys.map(&:to_s)
end

#remote(name, options) ⇒ Object

Adds a method to the model that calls the remote action for its data.

Example:

remote :posts_by_popularity, class_name: 'post'


219
220
221
222
223
224
225
# File 'lib/daylight/associations.rb', line 219

def remote name, options
  create_reflection(:remote, name, options).tap do |reflection|
    define_cached_method reflection.name do
      call_remote(reflection.name, reflection.klass)
    end
  end
end