Module: PlainRecord::Associations
- Included in:
- Model
- Defined in:
- lib/plain_record/associations.rb
Overview
Extention for model to store or have link to another model. There is two type of association.
Virtual property
In virtual method this definer create only link to another model. When you try to use this virtual property, model will find association object by rules in map.
Rules in map is only Hash with model properties in key and association properties in value. For example, if model contain name property and association must have post_name with same value, map will be { :name => :post_name }.
If you didn’t set map definer will try to find it automatically: it will find in model and association class all property pairs, what have name like property → model_property. For example, if model Post have property name and Comment have post_name, you may not set map – definer will find it automatically.
class Review
include PlainRecord::Resource
entry_in 'reviews/*.md'
virtual :author, one(Author)
property :author_login
text :review
end
class Author
include PlainRecord::Resource
list_in 'authors.yml'
virtual :reviews, many(Review)
property :login
property :name
end
Real property
If you will use this definer in property method, association object data will store in you model file. For example model:
class Movie
include PlainRecord::Resource
property :title
property :genre
property :release_year
end
class Tag
include PlainRecord::Resource
property :name
end
class Review
include PlainRecord::Resource
entry_in 'reviews/*.md'
property :author
property :movie, one(Movie)
property :tags, many(Tag)
text :review
end
will be store as:
author: John Smith
movie:
title: Watchmen
genre: action
release_year: 2009
tags:
- name: Great movies
- name: Comics
---
Movie is great!
Instance Attribute Summary collapse
-
#association_cache ⇒ Object
Hash with cached values for virtual associations.
-
#association_maps ⇒ Object
Hash with map for virtual associations.
Class Method Summary collapse
-
.define_link_many(klass, model, name, map) ⇒ Object
Define that virtual property
nameinklasscontain links tomodelwitch are finded bymap. -
.define_link_one(klass, model, name, map) ⇒ Object
Define that virtual property
nameinklasscontain link tomodelwitch is finded bymap. -
.define_real_many(klass, property, model) ⇒ Object
Define, that
propertyinklasscontain in file array of data frommodelobjects. -
.define_real_one(klass, property, model) ⇒ Object
Define, that
propertyinklasscontain in file data frommodel. -
.map(from, to, prefix) ⇒ Object
Find properties pairs in
fromandtomodels, witch is likeprefix_from→to.
Instance Attribute Details
#association_cache ⇒ Object
Hash with cached values for virtual associations.
105 106 107 |
# File 'lib/plain_record/associations.rb', line 105 def association_cache @association_cache end |
#association_maps ⇒ Object
Hash with map for virtual associations.
102 103 104 |
# File 'lib/plain_record/associations.rb', line 102 def association_maps @association_maps end |
Class Method Details
.define_link_many(klass, model, name, map) ⇒ Object
Define that virtual property name in klass contain links to model witch are finded by map.
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/plain_record/associations.rb', line 246 def define_link_many(klass, model, name, map) klass.association_cache ||= { } klass.association_maps ||= { } klass.association_maps[name] = map klass.class_eval <<-EOS, __FILE__, __LINE__ def #{name} unless self.class.association_cache[:#{name}] search = Hash[ self.class.association_maps[:#{name}].map do |from, to| [from, send(to)] end] self.class.association_cache[:#{name}] = AssociationProxy.new( #{model}.all(search), self, :#{name}) end self.class.association_cache[:#{name}] end def #{name}=(values) self.class.association_cache[:#{name}] = AssociationProxy.link( values, self, :#{name}) end EOS end |
.define_link_one(klass, model, name, map) ⇒ Object
Define that virtual property name in klass contain link to model witch is finded by map.
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/plain_record/associations.rb', line 219 def define_link_one(klass, model, name, map) klass.association_cache ||= { } klass.association_maps ||= { } klass.association_maps[name] = map klass.class_eval <<-EOS, __FILE__, __LINE__ def #{name} unless self.class.association_cache[:#{name}] search = Hash[ self.class.association_maps[:#{name}].map do |from, to| [to, send(from)] end] self.class.association_cache[:#{name}] = #{model}.first(search) end self.class.association_cache[:#{name}] end def #{name}=(value) self.class.association_maps[:#{name}].each do |from, to| value.send(to.to_s + '=', send(from)) end self.class.association_cache[:#{name}] = value end EOS end |
.define_real_many(klass, property, model) ⇒ Object
Define, that property in klass contain in file array of data from model objects.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/plain_record/associations.rb', line 169 def define_real_many(klass, property, model) name = property.to_s klass.after :load do |result, entry| if entry.data[name].is_a? Enumerable entry.data[name].map! { |i| model.new(entry.file, i) } else entry.data[name] = [] end result end klass.before :save do |entry| if entry.data[name].empty? entry.data.delete(name) else entry.data[name].map! do |obj| model.call_before_callbacks(:save, [obj]) obj.data end end end klass.after :save do |result, entry| entry.data[name].map! { |i| model.new(entry.file, i) } entry.data[name].each do |i| model.call_after_callbacks(:save, nil, [i]) end result end end |
.define_real_one(klass, property, model) ⇒ Object
Define, that property in klass contain in file data from model.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/plain_record/associations.rb', line 150 def define_real_one(klass, property, model) name = property.to_s klass.after :load do |result, entry| entry.data[name] = model.new(entry.file, entry.data[name]) result end klass.before :save do |entry| model.call_before_callbacks(:save, [entry.data[name]]) entry.data[name] = entry.data[name] end klass.after :save do |result, entry| entry.data[name] = model.new(entry.file, entry.data[name]) model.call_after_callbacks(:save, nil, [entry.data[name]]) result end end |
.map(from, to, prefix) ⇒ Object
Find properties pairs in from and to models, witch is like prefix_from → to.
For example, if Comment contain post_name property and Post contain name:
Associations.map(Comment, Post, :post) #=> { :post_name => :name }
205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/plain_record/associations.rb', line 205 def map(from, to, prefix) from_fields = (from.properties + from.virtuals).map { |i| i.to_s } mapped = { } (to.properties + to.virtuals).each do |to_field| from_field = prefix + to_field.to_s if from_fields.include? from_field mapped[from_field.to_sym] = to_field end end mapped end |